From 25478a0ad13f7eff93d2a3d565a883c0a0b92f0d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 04:20:12 +0000 Subject: [PATCH 1/3] Keep review graphs aligned with the walk that produced them. Empty impact ranges were classified as leaf UI and inherited every architecture finding, so checklist items pointed at nodes the review graph did not contain. Scope findings to the walk, extract permission classes and dataclasses onto the map, and show an empty-walk state instead of a missing-index message. Co-authored-by: zord.lack.net --- src/loadpath/architecture/snapshot.py | 2 ++ src/loadpath/extractors/django.py | 51 +++++++++++++++++++++++---- src/loadpath/index.py | 2 +- src/loadpath/review/engine.py | 3 +- src/loadpath/review/experience.py | 6 ++++ tests/unit/test_django_extractors.py | 49 +++++++++++++++++++++++++ tests/unit/test_experience.py | 21 +++++++++++ tests/unit/test_review_features.py | 25 +++++++++++-- ui/src/App.tsx | 2 +- ui/src/ImpactGraph.test.ts | 6 ++++ ui/src/ImpactGraph.tsx | 10 +++++- ui/src/styles.css | 9 ++++- 12 files changed, 171 insertions(+), 15 deletions(-) diff --git a/src/loadpath/architecture/snapshot.py b/src/loadpath/architecture/snapshot.py index d4ca208..9103b88 100644 --- a/src/loadpath/architecture/snapshot.py +++ b/src/loadpath/architecture/snapshot.py @@ -20,6 +20,8 @@ NodeType.SERIALIZER.value, NodeType.FORM.value, NodeType.MODEL.value, + NodeType.SERVICE.value, + NodeType.PERMISSION.value, NodeType.TASK.value, NodeType.MANAGEMENT_COMMAND.value, NodeType.SIGNAL.value, diff --git a/src/loadpath/extractors/django.py b/src/loadpath/extractors/django.py index 3315444..03fad5d 100644 --- a/src/loadpath/extractors/django.py +++ b/src/loadpath/extractors/django.py @@ -191,6 +191,27 @@ def _has_base(node: ast.ClassDef, names: set[str]) -> bool: return any((b.split(".")[-1] in names) for b in _bases(node)) +def _is_test_path(rel: str) -> bool: + path = Path(rel) + return path.name.startswith("test") or "/tests/" in f"/{rel}/" or path.name == "tests.py" + + +def _is_dataclass(node: ast.ClassDef) -> bool: + return any(name.split(".")[-1] == "dataclass" for name in _decorator_names(node)) + + +def _is_permission_class(node: ast.ClassDef) -> bool: + if node.name.startswith("Test"): + return False + if node.name.endswith("Permission"): + return True + return any( + part in {"BasePermission", "BasePermissionMetaclass", "TaigaResourcePermission", "ResourcePermission"} + for base in _bases(node) + for part in base.split(".") + ) + + def _decorator_names(node: ast.FunctionDef | ast.ClassDef | ast.AsyncFunctionDef) -> list[str]: out = [] for dec in node.decorator_list: @@ -444,8 +465,12 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None: self._admin(node) elif any(x.endswith("Config") for x in _bases(node)) or node.name.endswith("Config"): self._app_config(node) + elif _is_permission_class(node): + self._permission_class(node) elif "Service" in node.name or "UseCase" in node.name: self._service_class(node) + elif _is_dataclass(node) and not _is_test_path(self.rel_path): + self._service_class(node) self.generic_visit(node) self.class_stack.pop() @@ -796,6 +821,16 @@ def _admin(self, node: ast.ClassDef) -> None: qname = f"{self.app}.{node.name}" self.add_node(NodeType.ADMIN, node.name, qname, node.lineno, _with_doc({"app": self.app}, node)) + def _permission_class(self, node: ast.ClassDef) -> None: + qname = f"{self.app}.{node.name}" + self.add_node( + NodeType.PERMISSION, + node.name, + qname, + node.lineno, + _with_doc({"app": self.app, "permission_class": True}, node), + ) + def _service_class(self, node: ast.ClassDef) -> None: qname = f"{self.app}.{node.name}" self.add_node(NodeType.SERVICE, node.name, qname, node.lineno, _with_doc({"app": self.app}, node)) @@ -1570,11 +1605,7 @@ def _maybe_command(self, node: ast.FunctionDef) -> None: self.add_node(NodeType.MANAGEMENT_COMMAND, cmd, f"{self.app}.{cmd}", node.lineno, {"app": self.app}) def _maybe_test(self, node: ast.FunctionDef) -> None: - is_test_file = ( - Path(self.rel_path).name.startswith("test") - or "/tests/" in f"/{self.rel_path}/" - or Path(self.rel_path).name == "tests.py" - ) + is_test_file = _is_test_path(self.rel_path) if not is_test_file: return if not (node.name.startswith("test_") or node.name.startswith("test")): @@ -1592,7 +1623,15 @@ def _maybe_test(self, node: ast.FunctionDef) -> None: # crude: referenced class names in the test become tested_by for child in ast.walk(node): if isinstance(child, ast.Name) and child.id[:1].isupper(): - for ntype in (NodeType.SERIALIZER, NodeType.FORM, NodeType.VIEW, NodeType.MODEL, NodeType.SERVICE, NodeType.RECEIVER): + for ntype in ( + NodeType.SERIALIZER, + NodeType.FORM, + NodeType.VIEW, + NodeType.MODEL, + NodeType.SERVICE, + NodeType.RECEIVER, + NodeType.PERMISSION, + ): self.add_edge( node_id(ntype, f"{self.app}.{child.id}"), test.id, diff --git a/src/loadpath/index.py b/src/loadpath/index.py index 28736b7..c130f02 100644 --- a/src/loadpath/index.py +++ b/src/loadpath/index.py @@ -23,7 +23,7 @@ PY_SKIP = {"migrations"} # still extract migrations, just not skip INDEX_EXTENSIONS = {".py", ".ts", ".tsx", ".js", ".jsx", ".html", ".htm", ".graphql", ".gql"} # Bump when extractor/stitch node identity changes so incremental indexes rebuild. -INDEX_REVISION = "14" +INDEX_REVISION = "15" _UPSERT_BATCH = 25 ProgressCallback = Callable[[dict[str, Any]], None] diff --git a/src/loadpath/review/engine.py b/src/loadpath/review/engine.py index 4df62c4..4dd3180 100644 --- a/src/loadpath/review/engine.py +++ b/src/loadpath/review/engine.py @@ -100,7 +100,7 @@ def classify_change(impact_nodes: list[dict], findings: list, seeds: list[dict] kinds.add(ChangeKind.CROSS_CONTEXT.value) if NodeType.SERVICE.value in types and ChangeKind.PUBLIC_CONTRACT.value not in kinds: kinds.add(ChangeKind.INTERNAL_SERVICE.value) - ui_only = types <= { + ui_only = bool(types) and types <= { NodeType.COMPONENT.value, NodeType.PAGE.value, NodeType.REACT_ROUTE.value, @@ -410,7 +410,6 @@ def run_review( for f in findings if (f.node_id and f.node_id in impact_ids) or (f.file_path and f.file_path in impact_files) - or not impact_ids ] residuals = collect_residuals(store, impact_nodes, diff) evolution = analyze_evolution(repo_root, diff, impact_nodes, config) diff --git a/src/loadpath/review/experience.py b/src/loadpath/review/experience.py index ab0d584..e4e937e 100644 --- a/src/loadpath/review/experience.py +++ b/src/loadpath/review/experience.py @@ -251,6 +251,12 @@ def checklist(review: dict[str, Any]) -> list[dict[str, Any]]: "action": "none", }, ) + if "nodes" in review: + ids = {n.get("id") for n in (review.get("nodes") or []) if n.get("id")} + for item in items: + nid = item.get("node_id") + if nid and nid not in ids: + item["node_id"] = None return items diff --git a/tests/unit/test_django_extractors.py b/tests/unit/test_django_extractors.py index fe59745..9964f65 100644 --- a/tests/unit/test_django_extractors.py +++ b/tests/unit/test_django_extractors.py @@ -759,6 +759,54 @@ def test_dead_serializer_dict_does_not_resolve_get_serializer_class(): assert any("get_serializer_class" in r for r in g.residuals) +def test_extracts_permission_class_and_dataclass_service(): + source = ( + "from dataclasses import dataclass\n" + "from rest_framework.permissions import BasePermission\n" + "\n" + "class InvoicePermission(BasePermission):\n" + " def has_permission(self, request, view):\n" + " return True\n" + "\n" + "@dataclass(frozen=True)\n" + "class ViewerAccess:\n" + " privileged: bool = False\n" + "\n" + "def test_viewer_access():\n" + " ViewerAccess(privileged=True)\n" + " InvoicePermission()\n" + ) + g = extract_django_file("backend/billing/access.py", source, _cfg()) + assert any(n.type is NodeType.PERMISSION and n.name == "InvoicePermission" for n in g.nodes) + assert any(n.type is NodeType.SERVICE and n.name == "ViewerAccess" for n in g.nodes) + tests = extract_django_file( + "backend/billing/tests/test_access.py", + "from billing.access import ViewerAccess, InvoicePermission\n" + "def test_viewer_access():\n" + " ViewerAccess()\n" + " InvoicePermission()\n", + _cfg(), + ) + dsts = {e.dst for e in tests.edges} + srcs = {e.src for e in tests.edges} + assert any("ViewerAccess" in s for s in srcs) + assert any("InvoicePermission" in s for s in srcs) + assert any("test_viewer_access" in d for d in dsts) + + +def test_dataclass_in_tests_is_not_a_service(): + source = ( + "from dataclasses import dataclass\n" + "@dataclass\n" + "class FixtureRow:\n" + " name: str\n" + "def test_row():\n" + " FixtureRow('x')\n" + ) + g = extract_django_file("backend/billing/tests/test_rows.py", source, _cfg()) + assert not any(n.type is NodeType.SERVICE and n.name == "FixtureRow" for n in g.nodes) + + def test_marshmallow_schema_is_not_ninja_when_router_imported(): source = ( "from ninja import Router\n" @@ -771,3 +819,4 @@ def test_marshmallow_schema_is_not_ninja_when_router_imported(): assert not any(n.extra.get("ninja_schema") for n in g.nodes) + diff --git a/tests/unit/test_experience.py b/tests/unit/test_experience.py index 2c0e386..2bd5120 100644 --- a/tests/unit/test_experience.py +++ b/tests/unit/test_experience.py @@ -128,6 +128,27 @@ def test_checklist_todos_for_blocker_and_untested(): assert "it('renders')" in (test_item.get("body") or "") +def test_checklist_drops_node_ids_missing_from_the_graph(): + items = checklist( + { + "nodes": [], + "confidence": {"level": "medium", "untested_sinks": []}, + "findings": [ + { + "rule": "queryset_nplusone", + "severity": "warning", + "message": "unrelated model", + "node_id": "django.model:order.AbstractOrder", + "waived": False, + } + ], + "contract_break": {"kind": "none"}, + } + ) + finding = next(i for i in items if i["kind"] == "finding") + assert finding["node_id"] is None + + def test_isolate_paths_keeps_only_source_to_sink(): nodes = [ {"id": "a", "type": "django.field", "name": "total"}, diff --git a/tests/unit/test_review_features.py b/tests/unit/test_review_features.py index dd16283..5ede328 100644 --- a/tests/unit/test_review_features.py +++ b/tests/unit/test_review_features.py @@ -3,14 +3,14 @@ from loadpath.review.auth import auth_path from loadpath.review.contract import classify_contract_break from loadpath.review.diff import DiffSet, FileDiff, git_diff -from loadpath.review.engine import run_review +from loadpath.review.engine import classify_change, run_review from loadpath.review.gate import FAIL_ON_CHOICES, gate_result, write_github_output from loadpath.review.suggested_tests import suggested_tests from loadpath.review.trend import confidence_trend from loadpath.review.whatif import simulate_node -from loadpath.types import ContractBreakKind +from loadpath.types import ChangeKind, ContractBreakKind -from tests.conftest import copy_fixture, git_init_with_main, prepare_review_repo +from tests.conftest import copy_fixture, git_commit_all, git_init_with_main, prepare_review_repo def test_contract_break_required_field_is_breaking(): @@ -216,3 +216,22 @@ def test_confidence_trend_compares_same_range(tmp_path): note = confidence_trend(store, base=first["base"] if "base" in first else None, head=None) store.close() assert note["note"] + + +def test_empty_impact_is_not_leaf_ui(): + assert ChangeKind.LEAF_UI.value not in classify_change([], []) + assert classify_change([], []) == [ChangeKind.INTERNAL_SERVICE.value] + + +def test_docs_only_review_does_not_attach_architecture_findings(tmp_path): + repo = prepare_review_repo(tmp_path) + (repo / "README.md").write_text("# docs only\n", encoding="utf-8") + git_commit_all(repo, "docs") + review = run_review(repo, base="HEAD~1", head="HEAD") + assert review["nodes"] == [] + assert review["edges"] == [] + assert "leaf_ui" not in review["change_kinds"] + assert review["findings"] == [] + for item in review["checklist"]: + assert not item.get("node_id") + diff --git a/ui/src/App.tsx b/ui/src/App.tsx index e510e8b..f5d84b5 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1445,7 +1445,7 @@ export function App() { Tests - {graphNodes.length ? ( + {graphNodes.length || review || architecture?.indexed ? ( { expect(rfEdges.find((e) => e.id === "ok")?.label).toBe("uses serializer"); expect(rfEdges.find((e) => e.id === "other")?.label).toBeUndefined(); }); + + it("layouts an empty walk without nodes or edges", () => { + const { rfNodes, rfEdges } = toReactFlowElements([], []); + expect(rfNodes).toEqual([]); + expect(rfEdges).toEqual([]); + }); }); diff --git a/ui/src/ImpactGraph.tsx b/ui/src/ImpactGraph.tsx index 449efe1..3f61d1d 100644 --- a/ui/src/ImpactGraph.tsx +++ b/ui/src/ImpactGraph.tsx @@ -738,7 +738,15 @@ export function ImpactGraph({
- {view === "3d" ? ( + {nodes.length === 0 ? ( +
+

No typed nodes on this walk

+

+ This range did not hit models, views, routes, or React pages Loadpath extracts. Open the + architecture map for the indexed graph. +

+
+ ) : view === "3d" ? (

Architecture layers are stacked in depth (Django → stitch → React). Drag to orbit, scroll to diff --git a/ui/src/styles.css b/ui/src/styles.css index 9546f75..a37355a 100644 --- a/ui/src/styles.css +++ b/ui/src/styles.css @@ -1434,7 +1434,14 @@ h2 { font-size: 13px; margin: 0; font-weight: 600; } min-height: 220px; padding: 48px 16px; } -.empty h2 { font-size: 16px; color: var(--ink); margin-bottom: 8px; } +.graph-walk-empty { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + max-width: 36rem; + margin: 0 auto; +} .empty ol { margin: 12px 0 0 18px; padding: 0; } .empty code, code { font-family: var(--mono); font-size: 12px; color: var(--accent); } .btn-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } From 8b30cdcf755cd298c0604f1b6c47c7b27bef5e59 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 04:24:30 +0000 Subject: [PATCH 2/3] Rebuild the served UI bundle for empty-walk graph copy. Co-authored-by: zord.lack.net --- ...{LayeredGraph3D-Ch8n5xd0.js => LayeredGraph3D-Vlmu5bb6.js} | 2 +- .../static/assets/{index-BuTg-qls.js => index-X7ZCWUII.js} | 2 +- .../static/assets/{index-CdW5Vb1S.css => index-eMEYJf2U.css} | 2 +- src/loadpath/static/index.html | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/loadpath/static/assets/{LayeredGraph3D-Ch8n5xd0.js => LayeredGraph3D-Vlmu5bb6.js} (99%) rename src/loadpath/static/assets/{index-BuTg-qls.js => index-X7ZCWUII.js} (85%) rename src/loadpath/static/assets/{index-CdW5Vb1S.css => index-eMEYJf2U.css} (80%) diff --git a/src/loadpath/static/assets/LayeredGraph3D-Ch8n5xd0.js b/src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js similarity index 99% rename from src/loadpath/static/assets/LayeredGraph3D-Ch8n5xd0.js rename to src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js index 276baf9..092ec0e 100644 --- a/src/loadpath/static/assets/LayeredGraph3D-Ch8n5xd0.js +++ b/src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js @@ -1,4 +1,4 @@ -import{r as un,l as tc,c as nc,a as ic,L as sc,j as ei,t as rc}from"./index-BuTg-qls.js";/** +import{r as un,l as tc,c as nc,a as ic,L as sc,j as ei,t as rc}from"./index-X7ZCWUII.js";/** * @license * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/src/loadpath/static/assets/index-BuTg-qls.js b/src/loadpath/static/assets/index-X7ZCWUII.js similarity index 85% rename from src/loadpath/static/assets/index-BuTg-qls.js rename to src/loadpath/static/assets/index-X7ZCWUII.js index 6f3ec9c..2b7ec6b 100644 --- a/src/loadpath/static/assets/index-BuTg-qls.js +++ b/src/loadpath/static/assets/index-X7ZCWUII.js @@ -59,4 +59,4 @@ Error generating stack: `+m.message+` `,` +`).split(` `)),x=y.reduce((v,g)=>v.concat(...g),[]);return[y,x]}return[[],[]]},[t]);return L.useEffect(()=>{const p=(r==null?void 0:r.target)??ep,y=(r==null?void 0:r.actInsideInputWithModifier)??!0;if(t!==null){const x=_=>{var b,E;if(a.current=_.ctrlKey||_.metaKey||_.shiftKey||_.altKey,(!a.current||a.current&&!y)&&kg(_))return!1;const N=np(_.code,h);if(u.current.add(_[N]),tp(c,u.current,!1)){const I=((E=(b=_.composedPath)==null?void 0:b.call(_))==null?void 0:E[0])||_.target,w=(I==null?void 0:I.nodeName)==="BUTTON"||(I==null?void 0:I.nodeName)==="A";r.preventDefault!==!1&&(a.current||!w)&&_.preventDefault(),s(!0)}},v=_=>{const S=np(_.code,h);tp(c,u.current,!0)?(s(!1),u.current.clear()):u.current.delete(_[S]),_.key==="Meta"&&u.current.clear(),a.current=!1},g=()=>{u.current.clear(),s(!1)};return p==null||p.addEventListener("keydown",x),p==null||p.addEventListener("keyup",v),window.addEventListener("blur",g),window.addEventListener("contextmenu",g),()=>{p==null||p.removeEventListener("keydown",x),p==null||p.removeEventListener("keyup",v),window.removeEventListener("blur",g),window.removeEventListener("contextmenu",g)}}},[t,s]),o}function tp(t,r,o){return t.filter(s=>o||s.length===r.size).some(s=>s.every(a=>r.has(a)))}function np(t,r){return r.includes(t)?"code":"key"}const D_=()=>{const t=Ge();return L.useMemo(()=>({zoomIn:async r=>{const{panZoom:o}=t.getState();return o?o.scaleBy(1.2,r):!1},zoomOut:async r=>{const{panZoom:o}=t.getState();return o?o.scaleBy(1/1.2,r):!1},zoomTo:async(r,o)=>{const{panZoom:s}=t.getState();return s?s.scaleTo(r,o):!1},getZoom:()=>t.getState().transform[2],setViewport:async(r,o)=>{const{transform:[s,a,u],panZoom:c}=t.getState();return c?(await c.setViewport({x:r.x??s,y:r.y??a,zoom:r.zoom??u},o),!0):!1},getViewport:()=>{const[r,o,s]=t.getState().transform;return{x:r,y:o,zoom:s}},setCenter:async(r,o,s)=>t.getState().setCenter(r,o,s),fitBounds:async(r,o)=>{const{width:s,height:a,minZoom:u,maxZoom:c,panZoom:h}=t.getState(),p=Pc(r,s,a,u,c,(o==null?void 0:o.padding)??.1);return h?(await h.setViewport(p,{duration:o==null?void 0:o.duration,ease:o==null?void 0:o.ease,interpolate:o==null?void 0:o.interpolate}),!0):!1},screenToFlowPosition:(r,o={})=>{const{transform:s,snapGrid:a,snapToGrid:u,domNode:c}=t.getState();if(!c)return r;const{x:h,y:p}=c.getBoundingClientRect(),y={x:r.x-h,y:r.y-p},x=o.snapGrid??a,v=o.snapToGrid??u;return xs(y,s,v,x)},flowToScreenPosition:r=>{const{transform:o,domNode:s}=t.getState();if(!s)return r;const{x:a,y:u}=s.getBoundingClientRect(),c=ri(r,o);return{x:c.x+a,y:c.y+u}}}),[])};function Ug(t,r){const o=[],s=new Map,a=[];for(const u of t)if(u.type==="add"){a.push(u);continue}else if(u.type==="remove"||u.type==="replace")s.set(u.id,[u]);else{const c=s.get(u.id);c?c.push(u):s.set(u.id,[u])}for(const u of r){const c=s.get(u.id);if(!c){o.push(u);continue}if(c[0].type==="remove")continue;if(c[0].type==="replace"){o.push({...c[0].item});continue}const h={...u};for(const p of c)O_(p,h);o.push(h)}return a.length&&a.forEach(u=>{u.index!==void 0?o.splice(u.index,0,{...u.item}):o.push({...u.item})}),o}function O_(t,r){switch(t.type){case"select":{r.selected=t.selected;break}case"position":{typeof t.position<"u"&&(r.position=t.position),typeof t.dragging<"u"&&(r.dragging=t.dragging);break}case"dimensions":{typeof t.dimensions<"u"&&(r.measured={...t.dimensions},t.setAttributes&&((t.setAttributes===!0||t.setAttributes==="width")&&(r.width=t.dimensions.width),(t.setAttributes===!0||t.setAttributes==="height")&&(r.height=t.dimensions.height))),typeof t.resizing=="boolean"&&(r.resizing=t.resizing);break}}}function F_(t,r){return Ug(t,r)}function H_(t,r){return Ug(t,r)}function ao(t,r){return{id:t,type:"select",selected:r}}function Ko(t,r=new Set,o=!1){const s=[];for(const[a,u]of t){const c=r.has(a);!(u.selected===void 0&&!c)&&u.selected!==c&&(o&&(u.selected=c),s.push(ao(u.id,c)))}return s}function rp({items:t=[],lookup:r}){var a;const o=[],s=new Map(t.map(u=>[u.id,u]));for(const[u,c]of t.entries()){const h=r.get(c.id),p=((a=h==null?void 0:h.internals)==null?void 0:a.userNode)??h;p!==void 0&&p!==c&&o.push({id:c.id,item:c,type:"replace"}),p===void 0&&o.push({item:c,type:"add",index:u})}for(const[u]of r)s.get(u)===void 0&&o.push({id:u,type:"remove"});return o}function op(t){return{id:t.id,type:"remove"}}const B_=xg();function V_(t,r,o={}){return b1(t,r,{...o,onError:o.onError??B_})}const ip=t=>d1(t),W_=t=>pg(t);function Gg(t){return L.forwardRef(t)}const Yg=typeof window<"u"?L.useLayoutEffect:L.useEffect;function sp(t){const[r,o]=L.useState(BigInt(0)),[s]=L.useState(()=>U_(()=>o(a=>a+BigInt(1))));return Yg(()=>{const a=s.get();a.length&&(t(a),s.reset())},[r]),s}function U_(t){let r=[];return{get:()=>r,reset:()=>{r=[]},push:o=>{r.push(o),t()}}}const Xg=L.createContext(null);function G_({children:t}){const r=Ge(),o=L.useCallback(h=>{const{nodes:p=[],setNodes:y,hasDefaultNodes:x,onNodesChange:v,nodeLookup:g,fitViewQueued:_,onNodesChangeMiddlewareMap:S}=r.getState();let N=p;for(const E of h)N=typeof E=="function"?E(N):E;let b=rp({items:N,lookup:g});for(const E of S.values())b=E(b);x&&y(N),b.length>0?v==null||v(b):_&&window.requestAnimationFrame(()=>{const{fitViewQueued:E,nodes:I,setNodes:w}=r.getState();E&&w(I)})},[]),s=sp(o),a=L.useCallback(h=>{const{edges:p=[],setEdges:y,hasDefaultEdges:x,onEdgesChange:v,edgeLookup:g}=r.getState();let _=p;for(const S of h)_=typeof S=="function"?S(_):S;x?y(_):v&&v(rp({items:_,lookup:g}))},[]),u=sp(a),c=L.useMemo(()=>({nodeQueue:s,edgeQueue:u}),[]);return d.jsx(Xg.Provider,{value:c,children:t})}function Y_(){const t=L.useContext(Xg);if(!t)throw new Error("useBatchContext must be used within a BatchProvider");return t}const X_=t=>!!t.panZoom;function ll(){const t=D_(),r=Ge(),o=Y_(),s=De(X_),a=L.useMemo(()=>{const u=v=>r.getState().nodeLookup.get(v),c=v=>{o.nodeQueue.push(v)},h=v=>{o.edgeQueue.push(v)},p=v=>{var E,I;const{nodeLookup:g,nodeOrigin:_}=r.getState(),S=ip(v)?v:g.get(v.id),N=S.parentId?_g(S.position,S.measured,S.parentId,g,_):S.position,b={...S,position:N,width:((E=S.measured)==null?void 0:E.width)??S.width,height:((I=S.measured)==null?void 0:I.height)??S.height};return cs(b)},y=(v,g,_={replace:!1})=>{c(S=>S.map(N=>{if(N.id===v){const b=typeof g=="function"?g(N):g;return _.replace&&ip(b)?b:{...N,...b}}return N}))},x=(v,g,_={replace:!1})=>{h(S=>S.map(N=>{if(N.id===v){const b=typeof g=="function"?g(N):g;return _.replace&&W_(b)?b:{...N,...b}}return N}))};return{getNodes:()=>r.getState().nodes.map(v=>({...v})),getNode:v=>{var g;return(g=u(v))==null?void 0:g.internals.userNode},getInternalNode:u,getEdges:()=>{const{edges:v=[]}=r.getState();return v.map(g=>({...g}))},getEdge:v=>r.getState().edgeLookup.get(v),setNodes:c,setEdges:h,addNodes:v=>{const g=Array.isArray(v)?v:[v];o.nodeQueue.push(_=>[..._,...g])},addEdges:v=>{const g=Array.isArray(v)?v:[v];o.edgeQueue.push(_=>[..._,...g])},toObject:()=>{const{nodes:v=[],edges:g=[],transform:_}=r.getState(),[S,N,b]=_;return{nodes:v.map(E=>({...E})),edges:g.map(E=>({...E})),viewport:{x:S,y:N,zoom:b}}},deleteElements:async({nodes:v=[],edges:g=[]})=>{const{nodes:_,edges:S,onNodesDelete:N,onEdgesDelete:b,triggerNodeChanges:E,triggerEdgeChanges:I,onDelete:w,onBeforeDelete:j}=r.getState(),{nodes:A,edges:$}=await m1({nodesToRemove:v,edgesToRemove:g,nodes:_,edges:S,onBeforeDelete:j}),F=$.length>0,Y=A.length>0;if(F){const q=$.map(op);b==null||b($),I(q)}if(Y){const q=A.map(op);N==null||N(A),E(q)}return(Y||F)&&(w==null||w({nodes:A,edges:$})),{deletedNodes:A,deletedEdges:$}},getIntersectingNodes:(v,g=!0,_)=>{const S=Ph(v),N=S?v:p(v),b=_!==void 0;return N?(_||r.getState().nodes).filter(E=>{const I=r.getState().nodeLookup.get(E.id);if(I&&!S&&(E.id===v.id||!I.internals.positionAbsolute))return!1;const w=cs(b?E:I),j=Ga(w,N);return g&&j>0||j>=w.width*w.height||j>=N.width*N.height}):[]},isNodeIntersecting:(v,g,_=!0)=>{const N=Ph(v)?v:p(v);if(!N)return!1;const b=Ga(N,g);return _&&b>0||b>=g.width*g.height||b>=N.width*N.height},updateNode:y,updateNodeData:(v,g,_={replace:!1})=>{y(v,S=>{const N=typeof g=="function"?g(S):g;return _.replace?{...S,data:N}:{...S,data:{...S.data,...N}}},_)},updateEdge:x,updateEdgeData:(v,g,_={replace:!1})=>{x(v,S=>{const N=typeof g=="function"?g(S):g;return _.replace?{...S,data:N}:{...S,data:{...S.data,...N}}},_)},getNodesBounds:v=>{const{nodeLookup:g,nodeOrigin:_}=r.getState();return f1(v,{nodeLookup:g,nodeOrigin:_})},getHandleConnections:({type:v,id:g,nodeId:_})=>{var S;return Array.from(((S=r.getState().connectionLookup.get(`${_}-${v}${g?`-${g}`:""}`))==null?void 0:S.values())??[])},getNodeConnections:({type:v,handleId:g,nodeId:_})=>{var S;return Array.from(((S=r.getState().connectionLookup.get(`${_}${v?g?`-${v}-${g}`:`-${v}`:""}`))==null?void 0:S.values())??[])},fitView:async v=>{const g=r.getState().fitViewResolver??x1();return r.setState({fitViewQueued:!0,fitViewOptions:v,fitViewResolver:g}),o.nodeQueue.push(_=>[..._]),g.promise}}},[]);return L.useMemo(()=>({...a,...t,viewportInitialized:s}),[s])}const ap=t=>t.selected,q_=typeof window<"u"?window:void 0;function K_({deleteKeyCode:t,multiSelectionKeyCode:r}){const o=Ge(),{deleteElements:s}=ll(),a=fs(t,{actInsideInputWithModifier:!1}),u=fs(r,{target:q_});L.useEffect(()=>{if(a){const{edges:c,nodes:h}=o.getState();s({nodes:h.filter(ap),edges:c.filter(ap)}),o.setState({nodesSelectionActive:!1})}},[a]),L.useEffect(()=>{o.setState({multiSelectionActive:u})},[u])}function Q_(t){const r=Ge();L.useEffect(()=>{const o=()=>{var a,u,c,h;if(!t.current||!(((u=(a=t.current).checkVisibility)==null?void 0:u.call(a))??!0))return!1;const s=Ic(t.current);(s.height===0||s.width===0)&&((h=(c=r.getState()).onError)==null||h.call(c,"004",wn.error004())),r.setState({width:s.width||500,height:s.height||500})};if(t.current){o(),window.addEventListener("resize",o);const s=new ResizeObserver(()=>o());return s.observe(t.current),()=>{window.removeEventListener("resize",o),s&&t.current&&s.unobserve(t.current)}}},[])}const ul={position:"absolute",width:"100%",height:"100%",top:0,left:0},Z_=t=>({userSelectionActive:t.userSelectionActive,lib:t.lib,connectionInProgress:t.connection.inProgress});function J_({onPaneContextMenu:t,zoomOnScroll:r=!0,zoomOnPinch:o=!0,panOnScroll:s=!1,panActivationKeyPressed:a,panOnScrollSpeed:u=.5,panOnScrollMode:c=co.Free,zoomOnDoubleClick:h=!0,panOnDrag:p=!0,defaultViewport:y,translateExtent:x,minZoom:v,maxZoom:g,zoomActivationKeyCode:_,preventScrolling:S=!0,children:N,noWheelClassName:b,noPanClassName:E,onViewportChange:I,isControlledViewport:w,paneClickDistance:j,selectionOnDrag:A}){const $=Ge(),F=L.useRef(null),{userSelectionActive:Y,lib:q,connectionInProgress:re}=De(Z_,Qe),J=fs(_),te=L.useRef();Q_(F);const Q=L.useCallback(C=>{I==null||I({x:C[0],y:C[1],zoom:C[2]}),w||$.setState({transform:C})},[I,w]);return L.useEffect(()=>{if(F.current){te.current=n_({domNode:F.current,minZoom:v,maxZoom:g,translateExtent:x,viewport:y,onDraggingChange:U=>$.setState(M=>M.paneDragging===U?M:{paneDragging:U}),onPanZoomStart:(U,M)=>{const{onViewportChangeStart:D,onMoveStart:H}=$.getState();H==null||H(U,M),D==null||D(M)},onPanZoom:(U,M)=>{const{onViewportChange:D,onMove:H}=$.getState();H==null||H(U,M),D==null||D(M)},onPanZoomEnd:(U,M)=>{const{onViewportChangeEnd:D,onMoveEnd:H}=$.getState();H==null||H(U,M),D==null||D(M)}});const{x:C,y:V,zoom:W}=te.current.getViewport();return $.setState({panZoom:te.current,transform:[C,V,W],domNode:F.current.closest(".react-flow")}),()=>{var U;(U=te.current)==null||U.destroy()}}},[]),L.useEffect(()=>{var C;(C=te.current)==null||C.update({onPaneContextMenu:t,zoomOnScroll:r,zoomOnPinch:o,panOnScroll:s,panActivationKeyPressed:a,panOnScrollSpeed:u,panOnScrollMode:c,zoomOnDoubleClick:h,panOnDrag:p,zoomActivationKeyPressed:J,preventScrolling:S,noPanClassName:E,userSelectionActive:Y,noWheelClassName:b,lib:q,onTransformChange:Q,connectionInProgress:re,selectionOnDrag:A,paneClickDistance:j})},[t,r,o,s,a,u,c,h,p,J,S,E,Y,b,q,Q,re,A,j]),d.jsx("div",{className:"react-flow__renderer",ref:F,style:ul,children:N})}const eS=t=>({userSelectionActive:t.userSelectionActive,userSelectionRect:t.userSelectionRect});function tS(){const{userSelectionActive:t,userSelectionRect:r}=De(eS,Qe);return t&&r?d.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:r.width,height:r.height,transform:`translate(${r.x}px, ${r.y}px)`}}):null}const ec=(t,r)=>o=>{o.target===r.current&&(t==null||t(o))},nS=t=>({userSelectionActive:t.userSelectionActive,elementsSelectable:t.elementsSelectable,dragging:t.paneDragging,panBy:t.panBy,autoPanSpeed:t.autoPanSpeed});function rS({isSelecting:t,selectionKeyPressed:r,selectionMode:o=ls.Full,panOnDrag:s,autoPanOnSelection:a,paneClickDistance:u,selectionOnDrag:c,onSelectionStart:h,onSelectionEnd:p,onPaneClick:y,onPaneContextMenu:x,onPaneScroll:v,onPaneMouseEnter:g,onPaneMouseMove:_,onPaneMouseLeave:S,children:N}){const b=L.useRef(0),E=Ge(),{userSelectionActive:I,elementsSelectable:w,dragging:j,panBy:A,autoPanSpeed:$}=De(nS,Qe),F=w&&(t||I),Y=L.useRef(null),q=L.useRef(),re=L.useRef(new Set),J=L.useRef(new Set),te=L.useRef(!1),Q=L.useRef(!1),C=L.useRef({x:0,y:0}),V=L.useRef(!1),W=Z=>{if(Q.current||te.current||E.getState().connection.inProgress){Q.current=!1,te.current=!1;return}y==null||y(Z),E.getState().resetSelectedElements(),E.setState({nodesSelectionActive:!1})},U=Z=>{if(Array.isArray(s)&&(s!=null&&s.includes(2))){Z.preventDefault();return}x==null||x(Z)},M=v?Z=>v(Z):void 0,D=Z=>{Q.current&&(Z.stopPropagation(),Q.current=!1)},H=Z=>{var Le,nt;if(Z.pointerType==="touch"&&s!==!1&&!r)return;const{domNode:se,transform:me}=E.getState();if(q.current=se==null?void 0:se.getBoundingClientRect(),!q.current)return;const Ne=Z.target===Y.current;if(!Ne&&!!Z.target.closest(".nokey")||!t||!(c&&Ne||r)||Z.button!==0||!Z.isPrimary)return;(nt=(Le=Z.target)==null?void 0:Le.setPointerCapture)==null||nt.call(Le,Z.pointerId),Q.current=!1;const{x:Pe,y:ue}=xn(Z.nativeEvent,q.current),je=xs({x:Pe,y:ue},me);E.setState({userSelectionRect:{width:0,height:0,startX:je.x,startY:je.y,x:Pe,y:ue}}),Ne||(Z.stopPropagation(),Z.preventDefault())};function R(Z,se){const{userSelectionRect:me}=E.getState();if(!me)return;const{transform:Ne,nodeLookup:we,edgeLookup:ve,connectionLookup:Pe,triggerNodeChanges:ue,triggerEdgeChanges:je,defaultEdgeOptions:Le}=E.getState(),nt={x:me.startX,y:me.startY},{x:lt,y:ut}=ri(nt,Ne),Ye={startX:nt.x,startY:nt.y,x:Zmt.id)),J.current=new Set;const gt=(Le==null?void 0:Le.selectable)??!0;for(const mt of re.current){const Ct=Pe.get(mt);if(Ct)for(const{edgeId:ct}of Ct.values()){const et=ve.get(ct);et&&(et.selectable??gt)&&J.current.add(ct)}}if(!Ih(wt,re.current)){const mt=Ko(we,re.current,!0);ue(mt)}if(!Ih(Yt,J.current)){const mt=Ko(ve,J.current);je(mt)}E.setState({userSelectionRect:Ye,userSelectionActive:!0,nodesSelectionActive:!1})}function z(){if(!a||!q.current)return;const[Z,se]=Mc(C.current,q.current,$);A({x:Z,y:se}).then(me=>{if(!Q.current||!me){b.current=requestAnimationFrame(z);return}const{x:Ne,y:we}=C.current;R(Ne,we),b.current=requestAnimationFrame(z)})}const ne=()=>{cancelAnimationFrame(b.current),b.current=0,V.current=!1};L.useEffect(()=>()=>ne(),[]);const oe=Z=>{const{userSelectionRect:se,transform:me,resetSelectedElements:Ne}=E.getState();if(!q.current||!se)return;const{x:we,y:ve}=xn(Z.nativeEvent,q.current);C.current={x:we,y:ve};const Pe=ri({x:se.startX,y:se.startY},me);if(!Q.current){const ue=r?0:u;if(Math.hypot(we-Pe.x,ve-Pe.y)<=ue)return;Ne(),h==null||h(Z)}Q.current=!0,V.current||(z(),V.current=!0),R(we,ve)},fe=Z=>{var se,me;if(!F){Z.target===Y.current&&E.getState().connection.inProgress&&(te.current=!0);return}Z.button===0&&((me=(se=Z.target)==null?void 0:se.releasePointerCapture)==null||me.call(se,Z.pointerId),!I&&Z.target===Y.current&&E.getState().userSelectionRect&&(W==null||W(Z)),E.setState({userSelectionActive:!1,userSelectionRect:null}),Q.current&&(p==null||p(Z),E.setState({nodesSelectionActive:re.current.size>0})),ne())},he=Z=>{var se,me;(me=(se=Z.target)==null?void 0:se.releasePointerCapture)==null||me.call(se,Z.pointerId),ne()},pe=s===!0||Array.isArray(s)&&s.includes(0);return d.jsxs("div",{className:ot(["react-flow__pane",{draggable:pe,dragging:j,selection:t}]),onClick:F?void 0:ec(W,Y),onContextMenu:ec(U,Y),onWheel:ec(M,Y),onPointerEnter:F?void 0:g,onPointerMove:F?oe:_,onPointerUp:fe,onPointerCancel:F?he:void 0,onPointerDownCapture:F?H:void 0,onClickCapture:F?D:void 0,onPointerLeave:S,ref:Y,style:ul,children:[N,d.jsx(tS,{})]})}function vc({id:t,store:r,unselect:o=!1,nodeRef:s}){const{addSelectedNodes:a,unselectNodesAndEdges:u,multiSelectionActive:c,nodeLookup:h,onError:p}=r.getState(),y=h.get(t);if(!y){p==null||p("012",wn.error012(t));return}r.setState({nodesSelectionActive:!1}),y.selected?(o||y.selected&&c)&&(u({nodes:[y],edges:[]}),requestAnimationFrame(()=>{var x;return(x=s==null?void 0:s.current)==null?void 0:x.blur()})):a([t])}function qg({nodeRef:t,disabled:r=!1,noDragClassName:o,handleSelector:s,nodeId:a,isSelectable:u,nodeClickDistance:c}){const h=Ge(),[p,y]=L.useState(!1),x=L.useRef();return L.useEffect(()=>{if(!r)return x.current=B1({getStoreItems:()=>h.getState(),onNodeMouseDown:v=>{vc({id:v,store:h,nodeRef:t})},onDragStart:()=>{y(!0)},onDragStop:()=>{y(!1)}}),()=>{var v;(v=x.current)==null||v.destroy(),x.current=void 0}},[r,h,t]),L.useEffect(()=>{r||!t.current||!x.current||x.current.update({noDragClassName:o,handleSelector:s,domNode:t.current,isSelectable:u,nodeId:a,nodeClickDistance:c})},[o,s,r,u,t,a,c]),p}const oS=t=>r=>r.selected&&(r.draggable||t&&typeof r.draggable>"u");function Kg(){const t=Ge();return L.useCallback(o=>{const{nodeExtent:s,snapToGrid:a,snapGrid:u,nodesDraggable:c,onError:h,updateNodePositions:p,nodeLookup:y,nodeOrigin:x}=t.getState(),v=new Map,g=oS(c),_=a?u[0]:5,S=a?u[1]:5,N=o.direction.x*_*o.factor,b=o.direction.y*S*o.factor;for(const[,E]of y){if(!g(E))continue;let I={x:E.internals.positionAbsolute.x+N,y:E.internals.positionAbsolute.y+b};a&&(I=vs(I,u));const{position:w,positionAbsolute:j}=gg({nodeId:E.id,nextPosition:I,nodeLookup:y,nodeExtent:s,nodeOrigin:x,onError:h});E.position=w,E.internals.positionAbsolute=j,v.set(E.id,E)}p(v)},[])}const zc=L.createContext(null),iS=zc.Provider;zc.Consumer;const Qg=()=>L.useContext(zc),sS=t=>({connectOnClick:t.connectOnClick,noPanClassName:t.noPanClassName,rfId:t.rfId}),Zg=L.createContext(null);function aS({children:t}){const r=De(sS,Qe);return d.jsx(Zg.Provider,{value:r,children:t})}function lS(){const t=L.useContext(Zg);if(!t)throw new Error("useHandleConfig must be used within a HandleConfigProvider");return t}const uS={connectingFrom:!1,connectingTo:!1,clickConnecting:!1,isPossibleEndHandle:!0,connectionInProcess:!1,clickConnectionInProcess:!1,valid:!1},cS=(t,r,o)=>s=>{const{connectionClickStartHandle:a,connectionMode:u,connection:c}=s,{fromHandle:h,toHandle:p,isValid:y}=c;if(!h&&!a)return uS;const x=(p==null?void 0:p.nodeId)===t&&(p==null?void 0:p.id)===r&&(p==null?void 0:p.type)===o;return{connectingFrom:(h==null?void 0:h.nodeId)===t&&(h==null?void 0:h.id)===r&&(h==null?void 0:h.type)===o,connectingTo:x,clickConnecting:(a==null?void 0:a.nodeId)===t&&(a==null?void 0:a.id)===r&&(a==null?void 0:a.type)===o,isPossibleEndHandle:u===ti.Strict?(h==null?void 0:h.type)!==o:t!==(h==null?void 0:h.nodeId)||r!==(h==null?void 0:h.id),connectionInProcess:!!h,clickConnectionInProcess:!!a,valid:x&&y}};function dS({type:t="source",position:r=ke.Top,isValidConnection:o,isConnectable:s=!0,isConnectableStart:a=!0,isConnectableEnd:u=!0,id:c,onConnect:h,children:p,className:y,onMouseDown:x,onTouchStart:v,...g},_){var V,W;const S=c||null,N=t==="target",b=Ge(),E=Qg(),{connectOnClick:I,noPanClassName:w,rfId:j}=lS(),{connectingFrom:A,connectingTo:$,clickConnecting:F,isPossibleEndHandle:Y,connectionInProcess:q,clickConnectionInProcess:re,valid:J}=De(cS(E,S,t),Qe);E||(W=(V=b.getState()).onError)==null||W.call(V,"010",wn.error010());const te=U=>{const{defaultEdgeOptions:M,onConnect:D,hasDefaultEdges:H}=b.getState(),R={...M,...U};if(H){const{edges:z,setEdges:ne,onError:oe}=b.getState();ne(V_(R,z,{onError:oe}))}D==null||D(R),h==null||h(R)},Q=U=>{if(!E)return;const M=Ng(U.nativeEvent);if(a&&(M&&U.button===0||!M)){const D=b.getState();yc.onPointerDown(U.nativeEvent,{handleDomNode:U.currentTarget,autoPanOnConnect:D.autoPanOnConnect,connectionMode:D.connectionMode,connectionRadius:D.connectionRadius,domNode:D.domNode,nodeLookup:D.nodeLookup,lib:D.lib,isTarget:N,handleId:S,nodeId:E,flowId:D.rfId,panBy:D.panBy,cancelConnection:D.cancelConnection,onConnectStart:D.onConnectStart,onConnectEnd:(...H)=>{var R,z;return(z=(R=b.getState()).onConnectEnd)==null?void 0:z.call(R,...H)},updateConnection:D.updateConnection,onConnect:te,isValidConnection:o||((...H)=>{var R,z;return((z=(R=b.getState()).isValidConnection)==null?void 0:z.call(R,...H))??!0}),getTransform:()=>b.getState().transform,getFromHandle:()=>b.getState().connection.fromHandle,autoPanSpeed:D.autoPanSpeed,dragThreshold:D.connectionDragThreshold})}M?x==null||x(U):v==null||v(U)},C=U=>{const{onClickConnectStart:M,onClickConnectEnd:D,connectionClickStartHandle:H,connectionMode:R,isValidConnection:z,lib:ne,rfId:oe,nodeLookup:fe,connection:he}=b.getState();if(!E||!H&&!a)return;if(!H){M==null||M(U.nativeEvent,{nodeId:E,handleId:S,handleType:t}),b.setState({connectionClickStartHandle:{nodeId:E,type:t,id:S}});return}const pe=Sg(U.target),Z=o||z,{connection:se,isValid:me}=yc.isValid(U.nativeEvent,{handle:{nodeId:E,id:S,type:t},connectionMode:R,fromNodeId:H.nodeId,fromHandleId:H.id||null,fromType:H.type,isValidConnection:Z,flowId:oe,doc:pe,lib:ne,nodeLookup:fe});me&&se&&te(se);const Ne=structuredClone(he);delete Ne.inProgress,Ne.toPosition=Ne.toHandle?Ne.toHandle.position:null,D==null||D(U,Ne),b.setState({connectionClickStartHandle:null})};return d.jsx("div",{"data-handleid":S,"data-nodeid":E,"data-handlepos":r,"data-id":`${j}-${E}-${S}-${t}`,className:ot(["react-flow__handle",`react-flow__handle-${r}`,"nodrag",w,y,{source:!N,target:N,connectable:s,connectablestart:a,connectableend:u,clickconnecting:F,connectingfrom:A,connectingto:$,valid:J,connectionindicator:s&&(!q||Y)&&(q||re?u:a)}]),onMouseDown:Q,onTouchStart:Q,onClick:I?C:void 0,ref:_,...g,children:p})}const ii=L.memo(Gg(dS));function fS({data:t,isConnectable:r,sourcePosition:o=ke.Bottom}){return d.jsxs(d.Fragment,{children:[t==null?void 0:t.label,d.jsx(ii,{type:"source",position:o,isConnectable:r})]})}function hS({data:t,isConnectable:r,targetPosition:o=ke.Top,sourcePosition:s=ke.Bottom}){return d.jsxs(d.Fragment,{children:[d.jsx(ii,{type:"target",position:o,isConnectable:r}),t==null?void 0:t.label,d.jsx(ii,{type:"source",position:s,isConnectable:r})]})}function pS(){return null}function gS({data:t,isConnectable:r,targetPosition:o=ke.Top}){return d.jsxs(d.Fragment,{children:[d.jsx(ii,{type:"target",position:o,isConnectable:r}),t==null?void 0:t.label]})}const Xa={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},lp={input:fS,default:hS,output:gS,group:pS};function mS(t){var r,o,s,a;return t.internals.handleBounds===void 0?{width:t.width??t.initialWidth??((r=t.style)==null?void 0:r.width),height:t.height??t.initialHeight??((o=t.style)==null?void 0:o.height)}:{width:t.width??((s=t.style)==null?void 0:s.width),height:t.height??((a=t.style)==null?void 0:a.height)}}const yS=t=>{const{width:r,height:o,x:s,y:a}=ys(t.nodeLookup,{filter:u=>!!u.selected});return{width:vn(r)?r:null,height:vn(o)?o:null,userSelectionActive:t.userSelectionActive,transformString:`translate(${t.transform[0]}px,${t.transform[1]}px) scale(${t.transform[2]}) translate(${s}px,${a}px)`}};function vS({onSelectionContextMenu:t,noPanClassName:r,disableKeyboardA11y:o}){const s=Ge(),{width:a,height:u,transformString:c,userSelectionActive:h}=De(yS,Qe),p=Kg(),y=L.useRef(null);L.useEffect(()=>{var _;o||(_=y.current)==null||_.focus({preventScroll:!0})},[o]);const x=!h&&a!==null&&u!==null;if(qg({nodeRef:y,disabled:!x}),!x)return null;const v=t?_=>{const S=s.getState().nodes.filter(N=>N.selected);t(_,S)}:void 0,g=_=>{Object.prototype.hasOwnProperty.call(Xa,_.key)&&(_.preventDefault(),p({direction:Xa[_.key],factor:_.shiftKey?4:1}))};return d.jsx("div",{className:ot(["react-flow__nodesselection","react-flow__container",r]),style:{transform:c},children:d.jsx("div",{ref:y,className:"react-flow__nodesselection-rect",onContextMenu:v,tabIndex:o?void 0:-1,onKeyDown:o?void 0:g,style:{width:a,height:u}})})}const up=typeof window<"u"?window:void 0,xS=t=>({nodesSelectionActive:t.nodesSelectionActive,userSelectionActive:t.userSelectionActive});function Jg({children:t,onPaneClick:r,onPaneMouseEnter:o,onPaneMouseMove:s,onPaneMouseLeave:a,onPaneContextMenu:u,onPaneScroll:c,paneClickDistance:h,deleteKeyCode:p,selectionKeyCode:y,selectionOnDrag:x,selectionMode:v,onSelectionStart:g,onSelectionEnd:_,multiSelectionKeyCode:S,panActivationKeyCode:N,zoomActivationKeyCode:b,elementsSelectable:E,zoomOnScroll:I,zoomOnPinch:w,panOnScroll:j,panOnScrollSpeed:A,panOnScrollMode:$,zoomOnDoubleClick:F,panOnDrag:Y,autoPanOnSelection:q,defaultViewport:re,translateExtent:J,minZoom:te,maxZoom:Q,preventScrolling:C,onSelectionContextMenu:V,noWheelClassName:W,noPanClassName:U,disableKeyboardA11y:M,onViewportChange:D,isControlledViewport:H}){const{nodesSelectionActive:R,userSelectionActive:z}=De(xS,Qe),ne=fs(y,{target:up}),oe=fs(N,{target:up}),fe=oe||Y,he=oe||j,pe=x&&fe!==!0,Z=ne||z||pe;return K_({deleteKeyCode:p,multiSelectionKeyCode:S}),d.jsx(J_,{onPaneContextMenu:u,elementsSelectable:E,zoomOnScroll:I,zoomOnPinch:w,panOnScroll:he,panActivationKeyPressed:oe,panOnScrollSpeed:A,panOnScrollMode:$,zoomOnDoubleClick:F,panOnDrag:!ne&&fe,defaultViewport:re,translateExtent:J,minZoom:te,maxZoom:Q,zoomActivationKeyCode:b,preventScrolling:C,noWheelClassName:W,noPanClassName:U,onViewportChange:D,isControlledViewport:H,paneClickDistance:h,selectionOnDrag:pe,children:d.jsxs(rS,{onSelectionStart:g,onSelectionEnd:_,onPaneClick:r,onPaneMouseEnter:o,onPaneMouseMove:s,onPaneMouseLeave:a,onPaneContextMenu:u,onPaneScroll:c,panOnDrag:fe,autoPanOnSelection:q,isSelecting:!!Z,selectionMode:v,selectionKeyPressed:ne,paneClickDistance:h,selectionOnDrag:pe,children:[t,R&&d.jsx(vS,{onSelectionContextMenu:V,noPanClassName:U,disableKeyboardA11y:M})]})})}Jg.displayName="FlowRenderer";const wS=L.memo(Jg),_S=t=>r=>t?Cc(r.nodeLookup,{x:0,y:0,width:r.width,height:r.height},r.transform,!0).map(o=>o.id):Array.from(r.nodeLookup.keys());function SS(t){return De(L.useCallback(_S(t),[t]),Qe)}const kS=t=>t.updateNodeInternals;function NS(){const t=De(kS),[r]=L.useState(()=>typeof ResizeObserver>"u"?null:new ResizeObserver(o=>{const s=new Map;o.forEach(a=>{const u=a.target.getAttribute("data-id");s.set(u,{id:u,nodeElement:a.target,force:!0})}),t(s)}));return L.useEffect(()=>()=>{r==null||r.disconnect()},[r]),r}function jS({node:t,nodeType:r,hasDimensions:o,resizeObserver:s}){const a=Ge(),u=L.useRef(null),c=L.useRef(null),h=L.useRef(t.sourcePosition),p=L.useRef(t.targetPosition),y=L.useRef(r),x=o&&!!t.internals.handleBounds;return L.useEffect(()=>{u.current&&!t.hidden&&(!x||c.current!==u.current)&&(c.current&&(s==null||s.unobserve(c.current)),s==null||s.observe(u.current),c.current=u.current)},[x,t.hidden]),L.useEffect(()=>()=>{c.current&&(s==null||s.unobserve(c.current),c.current=null)},[]),L.useEffect(()=>{if(u.current){const v=y.current!==r,g=h.current!==t.sourcePosition,_=p.current!==t.targetPosition;(v||g||_)&&(y.current=r,h.current=t.sourcePosition,p.current=t.targetPosition,a.getState().updateNodeInternals(new Map([[t.id,{id:t.id,nodeElement:u.current,force:!0}]])))}},[t.id,r,t.sourcePosition,t.targetPosition]),u}function bS({id:t,onClick:r,onMouseEnter:o,onMouseMove:s,onMouseLeave:a,onContextMenu:u,onDoubleClick:c,nodesDraggable:h,elementsSelectable:p,nodesConnectable:y,nodesFocusable:x,resizeObserver:v,noDragClassName:g,noPanClassName:_,disableKeyboardA11y:S,rfId:N,nodeTypes:b,nodeClickDistance:E,onError:I}){const{node:w,internals:j,isParent:A}=De(Z=>{const se=Z.nodeLookup.get(t),me=Z.parentLookup.has(t);return{node:se,internals:se.internals,isParent:me}},Qe);let $=w.type||"default",F=(b==null?void 0:b[$])||lp[$];F===void 0&&(I==null||I("003",wn.error003($)),$="default",F=(b==null?void 0:b.default)||lp.default);const Y=!!(w.draggable||h&&typeof w.draggable>"u"),q=!!(w.selectable||p&&typeof w.selectable>"u"),re=!!(w.connectable||y&&typeof w.connectable>"u"),J=!!(w.focusable||x&&typeof w.focusable>"u"),te=Ge(),Q=wg(w),C=jS({node:w,nodeType:$,hasDimensions:Q,resizeObserver:v}),V=qg({nodeRef:C,disabled:w.hidden||!Y,noDragClassName:g,handleSelector:w.dragHandle,nodeId:t,isSelectable:q,nodeClickDistance:E}),W=Kg();if(w.hidden)return null;const U=Sn(w),M=mS(w),D=q||Y||r||o||s||a,H=o?Z=>o(Z,{...j.userNode}):void 0,R=s?Z=>s(Z,{...j.userNode}):void 0,z=a?Z=>a(Z,{...j.userNode}):void 0,ne=u?Z=>u(Z,{...j.userNode}):void 0,oe=c?Z=>c(Z,{...j.userNode}):void 0,fe=Z=>{const{selectNodesOnDrag:se,nodeDragThreshold:me}=te.getState();q&&(!se||!Y||me>0)&&vc({id:t,store:te,nodeRef:C}),r&&r(Z,{...j.userNode})},he=Z=>{if(!(kg(Z.nativeEvent)||S)){if(cg.includes(Z.key)&&q){const se=Z.key==="Escape";vc({id:t,store:te,unselect:se,nodeRef:C})}else if(Y&&w.selected&&Object.prototype.hasOwnProperty.call(Xa,Z.key)){Z.preventDefault();const{ariaLabelConfig:se}=te.getState();te.setState({ariaLiveMessage:se["node.a11yDescription.ariaLiveMessage"]({direction:Z.key.replace("Arrow","").toLowerCase(),x:~~j.positionAbsolute.x,y:~~j.positionAbsolute.y})}),W({direction:Xa[Z.key],factor:Z.shiftKey?4:1})}}},pe=()=>{var Pe;if(S||!((Pe=C.current)!=null&&Pe.matches(":focus-visible")))return;const{transform:Z,width:se,height:me,autoPanOnNodeFocus:Ne,setCenter:we}=te.getState();if(!Ne)return;Cc(new Map([[t,w]]),{x:0,y:0,width:se,height:me},Z,!0).length>0||we(w.position.x+U.width/2,w.position.y+U.height/2,{zoom:Z[2]})};return d.jsx("div",{className:ot(["react-flow__node",`react-flow__node-${$}`,{[_]:Y},w.className,{selected:w.selected,selectable:q,parent:A,draggable:Y,dragging:V}]),ref:C,style:{zIndex:j.z,transform:`translate(${j.positionAbsolute.x}px,${j.positionAbsolute.y}px)`,pointerEvents:D?"all":"none",visibility:Q?"visible":"hidden",...w.style,...M},"data-id":t,"data-testid":`rf__node-${t}`,onMouseEnter:H,onMouseMove:R,onMouseLeave:z,onContextMenu:ne,onClick:fe,onDoubleClick:oe,onKeyDown:J?he:void 0,tabIndex:J?0:void 0,onFocus:J?pe:void 0,role:w.ariaRole??(J?"group":void 0),"aria-roledescription":"node","aria-describedby":S?void 0:`${Bg}-${N}`,"aria-label":w.ariaLabel,...w.domAttributes,children:d.jsx(iS,{value:t,children:d.jsx(F,{id:t,data:w.data,type:$,positionAbsoluteX:j.positionAbsolute.x,positionAbsoluteY:j.positionAbsolute.y,selected:w.selected??!1,selectable:q,draggable:Y,deletable:w.deletable??!0,isConnectable:re,sourcePosition:w.sourcePosition,targetPosition:w.targetPosition,dragging:V,dragHandle:w.dragHandle,zIndex:j.z,parentId:w.parentId,...U})})})}var ES=L.memo(bS);const CS=t=>({nodesConnectable:t.nodesConnectable,nodesFocusable:t.nodesFocusable,elementsSelectable:t.elementsSelectable,onError:t.onError});function em(t){const{nodesConnectable:r,nodesFocusable:o,elementsSelectable:s,onError:a}=De(CS,Qe),u=SS(t.onlyRenderVisibleElements),c=NS();return d.jsx("div",{className:"react-flow__nodes",style:ul,children:u.map(h=>d.jsx(ES,{id:h,nodeTypes:t.nodeTypes,nodeExtent:t.nodeExtent,onClick:t.onNodeClick,onMouseEnter:t.onNodeMouseEnter,onMouseMove:t.onNodeMouseMove,onMouseLeave:t.onNodeMouseLeave,onContextMenu:t.onNodeContextMenu,onDoubleClick:t.onNodeDoubleClick,noDragClassName:t.noDragClassName,noPanClassName:t.noPanClassName,rfId:t.rfId,disableKeyboardA11y:t.disableKeyboardA11y,resizeObserver:c,nodesDraggable:t.nodesDraggable??!0,nodesConnectable:r,nodesFocusable:o,elementsSelectable:s,nodeClickDistance:t.nodeClickDistance,onError:a},h))})}em.displayName="NodeRenderer";const MS=L.memo(em);function PS(t){return De(L.useCallback(o=>{if(!t)return o.edges.map(a=>a.id);const s=[];if(o.width&&o.height)for(const a of o.edges){const u=o.nodeLookup.get(a.source),c=o.nodeLookup.get(a.target);u&&c&&k1({sourceNode:u,targetNode:c,width:o.width,height:o.height,transform:o.transform})&&s.push(a.id)}return s},[t]),Qe)}const IS=({color:t="none",strokeWidth:r=1})=>{const o={strokeWidth:r,...t&&{stroke:t}};return d.jsx("polyline",{className:"arrow",style:o,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},RS=({color:t="none",strokeWidth:r=1})=>{const o={strokeWidth:r,...t&&{stroke:t,fill:t}};return d.jsx("polyline",{className:"arrowclosed",style:o,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},cp={[us.Arrow]:IS,[us.ArrowClosed]:RS};function TS(t){const r=Ge();return L.useMemo(()=>{var a,u;return Object.prototype.hasOwnProperty.call(cp,t)?cp[t]:((u=(a=r.getState()).onError)==null||u.call(a,"009",wn.error009(t)),null)},[t])}const LS=({id:t,type:r,color:o,width:s=12.5,height:a=12.5,markerUnits:u="strokeWidth",strokeWidth:c,orient:h="auto-start-reverse"})=>{const p=TS(r);return p?d.jsx("marker",{className:"react-flow__arrowhead",id:t,markerWidth:`${s}`,markerHeight:`${a}`,viewBox:"-10 -10 20 20",markerUnits:u,orient:h,refX:"0",refY:"0",children:d.jsx(p,{color:o,strokeWidth:c})}):null},tm=({defaultColor:t,rfId:r})=>{const o=De(u=>u.edges),s=De(u=>u.defaultEdgeOptions),a=L.useMemo(()=>I1(o,{id:r,defaultColor:t,defaultMarkerStart:s==null?void 0:s.markerStart,defaultMarkerEnd:s==null?void 0:s.markerEnd}),[o,s,r,t]);return a.length?d.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:d.jsx("defs",{children:a.map(u=>d.jsx(LS,{id:u.id,type:u.type,color:u.color,width:u.width,height:u.height,markerUnits:u.markerUnits,strokeWidth:u.strokeWidth,orient:u.orient},u.id))})}):null};tm.displayName="MarkerDefinitions";var AS=L.memo(tm);function nm({x:t,y:r,label:o,labelStyle:s,labelShowBg:a=!0,labelBgStyle:u,labelBgPadding:c=[2,4],labelBgBorderRadius:h=2,children:p,className:y,...x}){const[v,g]=L.useState({x:1,y:0,width:0,height:0}),_=ot(["react-flow__edge-textwrapper",y]),S=L.useRef(null);return L.useEffect(()=>{if(S.current){const N=S.current.getBBox();g({x:N.x,y:N.y,width:N.width,height:N.height})}},[o]),o?d.jsxs("g",{transform:`translate(${t-v.width/2} ${r-v.height/2})`,className:_,visibility:v.width?"visible":"hidden",...x,children:[a&&d.jsx("rect",{width:v.width+2*c[0],x:-c[0],y:-c[1],height:v.height+2*c[1],className:"react-flow__edge-textbg",style:u,rx:h,ry:h}),d.jsx("text",{className:"react-flow__edge-text",y:v.height/2,dy:"0.3em",ref:S,style:s,children:o}),p]}):null}nm.displayName="EdgeText";const $S=L.memo(nm);function ws({path:t,labelX:r,labelY:o,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:h,labelBgBorderRadius:p,interactionWidth:y=20,...x}){return d.jsxs(d.Fragment,{children:[d.jsx("path",{...x,d:t,fill:"none",className:ot(["react-flow__edge-path",x.className])}),y?d.jsx("path",{d:t,fill:"none",strokeOpacity:0,strokeWidth:y,className:"react-flow__edge-interaction"}):null,s&&vn(r)&&vn(o)?d.jsx($S,{x:r,y:o,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:h,labelBgBorderRadius:p}):null]})}function dp({pos:t,x1:r,y1:o,x2:s,y2:a}){return t===ke.Left||t===ke.Right?[.5*(r+s),o]:[r,.5*(o+a)]}function rm({sourceX:t,sourceY:r,sourcePosition:o=ke.Bottom,targetX:s,targetY:a,targetPosition:u=ke.Top}){const[c,h]=dp({pos:o,x1:t,y1:r,x2:s,y2:a}),[p,y]=dp({pos:u,x1:s,y1:a,x2:t,y2:r}),[x,v,g,_]=jg({sourceX:t,sourceY:r,targetX:s,targetY:a,sourceControlX:c,sourceControlY:h,targetControlX:p,targetControlY:y});return[`M${t},${r} C${c},${h} ${p},${y} ${s},${a}`,x,v,g,_]}function om(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,sourcePosition:c,targetPosition:h,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:E})=>{const[I,w,j]=rm({sourceX:o,sourceY:s,sourcePosition:c,targetX:a,targetY:u,targetPosition:h}),A=t.isInternal?void 0:r;return d.jsx(ws,{id:A,path:I,labelX:w,labelY:j,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:E})})}const zS=om({isInternal:!1}),im=om({isInternal:!0});zS.displayName="SimpleBezierEdge";im.displayName="SimpleBezierEdgeInternal";function sm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,sourcePosition:_=ke.Bottom,targetPosition:S=ke.Top,markerEnd:N,markerStart:b,pathOptions:E,interactionWidth:I})=>{const[w,j,A]=Ya({sourceX:o,sourceY:s,sourcePosition:_,targetX:a,targetY:u,targetPosition:S,borderRadius:E==null?void 0:E.borderRadius,offset:E==null?void 0:E.offset,stepPosition:E==null?void 0:E.stepPosition}),$=t.isInternal?void 0:r;return d.jsx(ws,{id:$,path:w,labelX:j,labelY:A,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:N,markerStart:b,interactionWidth:I})})}const am=sm({isInternal:!1}),lm=sm({isInternal:!0});am.displayName="SmoothStepEdge";lm.displayName="SmoothStepEdgeInternal";function um(t){return L.memo(({id:r,...o})=>{var a;const s=t.isInternal?void 0:r;return d.jsx(am,{...o,id:s,pathOptions:L.useMemo(()=>{var u;return{borderRadius:0,offset:(u=o.pathOptions)==null?void 0:u.offset}},[(a=o.pathOptions)==null?void 0:a.offset])})})}const DS=um({isInternal:!1}),cm=um({isInternal:!0});DS.displayName="StepEdge";cm.displayName="StepEdgeInternal";function dm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:_,markerStart:S,interactionWidth:N})=>{const[b,E,I]=Cg({sourceX:o,sourceY:s,targetX:a,targetY:u}),w=t.isInternal?void 0:r;return d.jsx(ws,{id:w,path:b,labelX:E,labelY:I,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:_,markerStart:S,interactionWidth:N})})}const OS=dm({isInternal:!1}),fm=dm({isInternal:!0});OS.displayName="StraightEdge";fm.displayName="StraightEdgeInternal";function hm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,sourcePosition:c=ke.Bottom,targetPosition:h=ke.Top,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,pathOptions:E,interactionWidth:I})=>{const[w,j,A]=bg({sourceX:o,sourceY:s,sourcePosition:c,targetX:a,targetY:u,targetPosition:h,curvature:E==null?void 0:E.curvature}),$=t.isInternal?void 0:r;return d.jsx(ws,{id:$,path:w,labelX:j,labelY:A,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:I})})}const FS=hm({isInternal:!1}),pm=hm({isInternal:!0});FS.displayName="BezierEdge";pm.displayName="BezierEdgeInternal";const fp={default:pm,straight:fm,step:cm,smoothstep:lm,simplebezier:im},hp={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null,zIndex:void 0},HS=(t,r,o)=>o===ke.Left?t-r:o===ke.Right?t+r:t,BS=(t,r,o)=>o===ke.Top?t-r:o===ke.Bottom?t+r:t,pp="react-flow__edgeupdater";function gp({position:t,centerX:r,centerY:o,radius:s=10,onMouseDown:a,onMouseEnter:u,onMouseOut:c,type:h}){return d.jsx("circle",{onMouseDown:a,onMouseEnter:u,onMouseOut:c,className:ot([pp,`${pp}-${h}`]),cx:HS(r,s,t),cy:BS(o,s,t),r:s,stroke:"transparent",fill:"transparent"})}function VS({isReconnectable:t,reconnectRadius:r,edge:o,sourceX:s,sourceY:a,targetX:u,targetY:c,sourcePosition:h,targetPosition:p,onReconnect:y,onReconnectStart:x,onReconnectEnd:v,setReconnecting:g,setUpdateHover:_}){const S=Ge(),N=(j,A)=>{if(j.button!==0)return;const{autoPanOnConnect:$,domNode:F,connectionMode:Y,connectionRadius:q,lib:re,onConnectStart:J,cancelConnection:te,nodeLookup:Q,rfId:C,panBy:V,updateConnection:W}=S.getState(),U=A.type==="target",M=(R,z)=>{g(!1),v==null||v(R,o,A.type,z)},D=R=>y==null?void 0:y(o,R),H=(R,z)=>{g(!0),x==null||x(j,o,A.type),J==null||J(R,z)};yc.onPointerDown(j.nativeEvent,{autoPanOnConnect:$,connectionMode:Y,connectionRadius:q,domNode:F,handleId:A.id,nodeId:A.nodeId,nodeLookup:Q,isTarget:U,edgeUpdaterType:A.type,lib:re,flowId:C,cancelConnection:te,panBy:V,isValidConnection:(...R)=>{var z,ne;return((ne=(z=S.getState()).isValidConnection)==null?void 0:ne.call(z,...R))??!0},onConnect:D,onConnectStart:H,onConnectEnd:(...R)=>{var z,ne;return(ne=(z=S.getState()).onConnectEnd)==null?void 0:ne.call(z,...R)},onReconnectEnd:M,updateConnection:W,getTransform:()=>S.getState().transform,getFromHandle:()=>S.getState().connection.fromHandle,dragThreshold:S.getState().connectionDragThreshold,handleDomNode:j.currentTarget})},b=j=>N(j,{nodeId:o.target,id:o.targetHandle??null,type:"target"}),E=j=>N(j,{nodeId:o.source,id:o.sourceHandle??null,type:"source"}),I=()=>_(!0),w=()=>_(!1);return d.jsxs(d.Fragment,{children:[(t===!0||t==="source")&&d.jsx(gp,{position:h,centerX:s,centerY:a,radius:r,onMouseDown:b,onMouseEnter:I,onMouseOut:w,type:"source"}),(t===!0||t==="target")&&d.jsx(gp,{position:p,centerX:u,centerY:c,radius:r,onMouseDown:E,onMouseEnter:I,onMouseOut:w,type:"target"})]})}function WS({id:t,edgesFocusable:r,edgesReconnectable:o,elementsSelectable:s,onClick:a,onDoubleClick:u,onContextMenu:c,onMouseEnter:h,onMouseMove:p,onMouseLeave:y,reconnectRadius:x,onReconnect:v,onReconnectStart:g,onReconnectEnd:_,rfId:S,edgeTypes:N,noPanClassName:b,onError:E,disableKeyboardA11y:I}){let w=De(we=>we.edgeLookup.get(t));const j=De(we=>we.defaultEdgeOptions);w=j?{...j,...w}:w;let A=w.type||"default",$=(N==null?void 0:N[A])||fp[A];$===void 0&&(E==null||E("011",wn.error011(A)),A="default",$=(N==null?void 0:N.default)||fp.default);const F=!!(w.focusable||r&&typeof w.focusable>"u"),Y=typeof v<"u"&&(w.reconnectable||o&&typeof w.reconnectable>"u"),q=!!(w.selectable||s&&typeof w.selectable>"u"),re=L.useRef(null),[J,te]=L.useState(!1),[Q,C]=L.useState(!1),V=Ge(),{zIndex:W=w.zIndex,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z}=De(L.useCallback(we=>{const ve=we.nodeLookup.get(w.source),Pe=we.nodeLookup.get(w.target);if(!ve||!Pe)return hp;const ue=P1({id:t,sourceNode:ve,targetNode:Pe,sourceHandle:w.sourceHandle||null,targetHandle:w.targetHandle||null,connectionMode:we.connectionMode,onError:E}),je=S1({selected:w.selected,zIndex:w.zIndex,sourceNode:ve,targetNode:Pe,elevateOnSelect:we.elevateEdgesOnSelect,zIndexMode:we.zIndexMode});return{...ue||hp,zIndex:je}},[w.source,w.target,w.sourceHandle,w.targetHandle,w.selected,w.zIndex,E]),Qe),ne=L.useMemo(()=>w.markerStart?`url('#${gc(w.markerStart,S)}')`:void 0,[w.markerStart,S]),oe=L.useMemo(()=>w.markerEnd?`url('#${gc(w.markerEnd,S)}')`:void 0,[w.markerEnd,S]);if(w.hidden||U===null||M===null||D===null||H===null)return null;const fe=we=>{var je;const{addSelectedEdges:ve,unselectNodesAndEdges:Pe,multiSelectionActive:ue}=V.getState();q&&(V.setState({nodesSelectionActive:!1}),w.selected&&ue?(Pe({nodes:[],edges:[w]}),(je=re.current)==null||je.blur()):ve([t])),a&&a(we,w)},he=u?we=>{u(we,{...w})}:void 0,pe=c?we=>{c(we,{...w})}:void 0,Z=h?we=>{h(we,{...w})}:void 0,se=p?we=>{p(we,{...w})}:void 0,me=y?we=>{y(we,{...w})}:void 0,Ne=we=>{var ve;if(!I&&cg.includes(we.key)&&q){const{unselectNodesAndEdges:Pe,addSelectedEdges:ue}=V.getState();we.key==="Escape"?((ve=re.current)==null||ve.blur(),Pe({edges:[w]})):ue([t])}};return d.jsx("svg",{style:{zIndex:W},children:d.jsxs("g",{className:ot(["react-flow__edge",`react-flow__edge-${A}`,w.className,b,{selected:w.selected,animated:w.animated,inactive:!q&&!a,updating:J,selectable:q}]),onClick:fe,onDoubleClick:he,onContextMenu:pe,onMouseEnter:Z,onMouseMove:se,onMouseLeave:me,onKeyDown:F?Ne:void 0,tabIndex:F?0:void 0,role:w.ariaRole??(F?"group":"img"),"aria-roledescription":"edge","data-id":t,"data-testid":`rf__edge-${t}`,"aria-label":w.ariaLabel===null?void 0:w.ariaLabel||`Edge from ${w.source} to ${w.target}`,"aria-describedby":F?`${Vg}-${S}`:void 0,ref:re,...w.domAttributes,children:[!Q&&d.jsx($,{id:t,source:w.source,target:w.target,type:w.type,selected:w.selected,animated:w.animated,selectable:q,deletable:w.deletable??!0,label:w.label,labelStyle:w.labelStyle,labelShowBg:w.labelShowBg,labelBgStyle:w.labelBgStyle,labelBgPadding:w.labelBgPadding,labelBgBorderRadius:w.labelBgBorderRadius,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z,data:w.data,style:w.style,sourceHandleId:w.sourceHandle,targetHandleId:w.targetHandle,markerStart:ne,markerEnd:oe,pathOptions:"pathOptions"in w?w.pathOptions:void 0,interactionWidth:w.interactionWidth}),Y&&d.jsx(VS,{edge:w,isReconnectable:Y,reconnectRadius:x,onReconnect:v,onReconnectStart:g,onReconnectEnd:_,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z,setUpdateHover:te,setReconnecting:C})]})})}var US=L.memo(WS);const GS=t=>({edgesFocusable:t.edgesFocusable,edgesReconnectable:t.edgesReconnectable,elementsSelectable:t.elementsSelectable,connectionMode:t.connectionMode,onError:t.onError});function gm({defaultMarkerColor:t,onlyRenderVisibleElements:r,rfId:o,edgeTypes:s,noPanClassName:a,onReconnect:u,onEdgeContextMenu:c,onEdgeMouseEnter:h,onEdgeMouseMove:p,onEdgeMouseLeave:y,onEdgeClick:x,reconnectRadius:v,onEdgeDoubleClick:g,onReconnectStart:_,onReconnectEnd:S,disableKeyboardA11y:N}){const{edgesFocusable:b,edgesReconnectable:E,elementsSelectable:I,onError:w}=De(GS,Qe),j=PS(r);return d.jsxs("div",{className:"react-flow__edges",children:[d.jsx(AS,{defaultColor:t,rfId:o}),j.map(A=>d.jsx(US,{id:A,edgesFocusable:b,edgesReconnectable:E,elementsSelectable:I,noPanClassName:a,onReconnect:u,onContextMenu:c,onMouseEnter:h,onMouseMove:p,onMouseLeave:y,onClick:x,reconnectRadius:v,onDoubleClick:g,onReconnectStart:_,onReconnectEnd:S,rfId:o,onError:w,edgeTypes:s,disableKeyboardA11y:N},A))]})}gm.displayName="EdgeRenderer";const YS=L.memo(gm),mp=t=>`translate(${t[0]}px,${t[1]}px) scale(${t[2]})`;function XS({children:t}){const r=Ge(),o=L.useRef(null),[s]=L.useState(()=>r.getState().transform);return Yg(()=>{let a=null;const u=()=>{const c=r.getState().transform;a&&c[0]===a[0]&&c[1]===a[1]&&c[2]===a[2]||(a=c,o.current&&(o.current.style.transform=mp(c)))};return u(),r.subscribe(u)},[r]),d.jsx("div",{ref:o,className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:mp(s)},children:t})}function qS(t){const r=ll(),o=L.useRef(!1);L.useEffect(()=>{!o.current&&r.viewportInitialized&&t&&(setTimeout(()=>t(r),1),o.current=!0)},[t,r.viewportInitialized])}const KS=t=>{var r;return(r=t.panZoom)==null?void 0:r.syncViewport};function QS(t){const r=De(KS),o=Ge();return L.useEffect(()=>{t&&(r==null||r(t),o.setState({transform:[t.x,t.y,t.zoom]}))},[t,r]),null}function ZS(t){return t.connection.inProgress?{...t.connection,to:xs(t.connection.to,t.transform)}:{...t.connection}}function JS(t){return ZS}function ek(t){const r=JS();return De(r,Qe)}const tk=t=>({nodesConnectable:t.nodesConnectable,isValid:t.connection.isValid,inProgress:t.connection.inProgress,width:t.width,height:t.height});function nk({containerStyle:t,style:r,type:o,component:s}){const{nodesConnectable:a,width:u,height:c,isValid:h,inProgress:p}=De(tk,Qe);return!(u&&a&&p)?null:d.jsx("svg",{style:t,width:u,height:c,className:"react-flow__connectionline react-flow__container",children:d.jsx("g",{className:ot(["react-flow__connection",hg(h)]),children:d.jsx(mm,{style:r,type:o,CustomComponent:s,isValid:h})})})}const mm=({style:t,type:r=$r.Bezier,CustomComponent:o,isValid:s})=>{const{inProgress:a,from:u,fromNode:c,fromHandle:h,fromPosition:p,to:y,toNode:x,toHandle:v,toPosition:g,pointer:_}=ek();if(!a)return;if(o)return d.jsx(o,{connectionLineType:r,connectionLineStyle:t,fromNode:c,fromHandle:h,fromX:u.x,fromY:u.y,toX:y.x,toY:y.y,fromPosition:p,toPosition:g,connectionStatus:hg(s),toNode:x,toHandle:v,pointer:_});let S="";const N={sourceX:u.x,sourceY:u.y,sourcePosition:p,targetX:y.x,targetY:y.y,targetPosition:g};switch(r){case $r.Bezier:[S]=bg(N);break;case $r.SimpleBezier:[S]=rm(N);break;case $r.Step:[S]=Ya({...N,borderRadius:0});break;case $r.SmoothStep:[S]=Ya(N);break;default:[S]=Cg(N)}return d.jsx("path",{d:S,fill:"none",className:"react-flow__connection-path",style:t})};mm.displayName="ConnectionLine";const rk={};function yp(t=rk){L.useRef(t),Ge(),L.useEffect(()=>{},[t])}function ok(){Ge(),L.useRef(!1),L.useEffect(()=>{},[])}function ym({nodeTypes:t,edgeTypes:r,onInit:o,onNodeClick:s,onEdgeClick:a,onNodeDoubleClick:u,onEdgeDoubleClick:c,onNodeMouseEnter:h,onNodeMouseMove:p,onNodeMouseLeave:y,onNodeContextMenu:x,onSelectionContextMenu:v,onSelectionStart:g,onSelectionEnd:_,connectionLineType:S,connectionLineStyle:N,connectionLineComponent:b,connectionLineContainerStyle:E,selectionKeyCode:I,selectionOnDrag:w,selectionMode:j,multiSelectionKeyCode:A,panActivationKeyCode:$,zoomActivationKeyCode:F,deleteKeyCode:Y,onlyRenderVisibleElements:q,elementsSelectable:re,defaultViewport:J,translateExtent:te,minZoom:Q,maxZoom:C,preventScrolling:V,defaultMarkerColor:W,zoomOnScroll:U,zoomOnPinch:M,panOnScroll:D,panOnScrollSpeed:H,panOnScrollMode:R,zoomOnDoubleClick:z,panOnDrag:ne,autoPanOnSelection:oe,onPaneClick:fe,onPaneMouseEnter:he,onPaneMouseMove:pe,onPaneMouseLeave:Z,onPaneScroll:se,onPaneContextMenu:me,paneClickDistance:Ne,nodeClickDistance:we,onEdgeContextMenu:ve,onEdgeMouseEnter:Pe,onEdgeMouseMove:ue,onEdgeMouseLeave:je,reconnectRadius:Le,onReconnect:nt,onReconnectStart:lt,onReconnectEnd:ut,noDragClassName:Ye,noWheelClassName:wt,noPanClassName:Yt,disableKeyboardA11y:gt,nodeExtent:mt,rfId:Ct,viewport:ct,onViewportChange:et,nodesDraggable:On}){return yp(t),yp(r),ok(),qS(o),QS(ct),d.jsx(wS,{onPaneClick:fe,onPaneMouseEnter:he,onPaneMouseMove:pe,onPaneMouseLeave:Z,onPaneContextMenu:me,onPaneScroll:se,paneClickDistance:Ne,deleteKeyCode:Y,selectionKeyCode:I,selectionOnDrag:w,selectionMode:j,onSelectionStart:g,onSelectionEnd:_,multiSelectionKeyCode:A,panActivationKeyCode:$,zoomActivationKeyCode:F,elementsSelectable:re,zoomOnScroll:U,zoomOnPinch:M,zoomOnDoubleClick:z,panOnScroll:D,panOnScrollSpeed:H,panOnScrollMode:R,panOnDrag:ne,autoPanOnSelection:oe,defaultViewport:J,translateExtent:te,minZoom:Q,maxZoom:C,onSelectionContextMenu:v,preventScrolling:V,noDragClassName:Ye,noWheelClassName:wt,noPanClassName:Yt,disableKeyboardA11y:gt,onViewportChange:et,isControlledViewport:!!ct,children:d.jsxs(XS,{children:[d.jsx(YS,{edgeTypes:r,onEdgeClick:a,onEdgeDoubleClick:c,onReconnect:nt,onReconnectStart:lt,onReconnectEnd:ut,onlyRenderVisibleElements:q,onEdgeContextMenu:ve,onEdgeMouseEnter:Pe,onEdgeMouseMove:ue,onEdgeMouseLeave:je,reconnectRadius:Le,defaultMarkerColor:W,noPanClassName:Yt,disableKeyboardA11y:gt,rfId:Ct}),d.jsx(nk,{style:N,type:S,component:b,containerStyle:E}),d.jsx("div",{className:"react-flow__edgelabel-renderer"}),d.jsx(MS,{nodeTypes:t,onNodeClick:s,onNodeDoubleClick:u,onNodeMouseEnter:h,onNodeMouseMove:p,onNodeMouseLeave:y,onNodeContextMenu:x,nodeClickDistance:we,onlyRenderVisibleElements:q,noPanClassName:Yt,noDragClassName:Ye,disableKeyboardA11y:gt,nodeExtent:mt,rfId:Ct,nodesDraggable:On}),d.jsx("div",{className:"react-flow__viewport-portal"})]})})}ym.displayName="GraphView";const ik=L.memo(ym),sk=xg(),vp=({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p=.5,maxZoom:y=2,nodeOrigin:x,nodeExtent:v,zIndexMode:g="basic"}={})=>{const _=new Map,S=new Map,N=new Map,b=new Map,E=s??r??[],I=o??t??[],w=x??[0,0],j=v??as;Ig(N,b,E);const{nodesInitialized:A}=mc(I,_,S,{nodeOrigin:w,nodeExtent:j,zIndexMode:g});let $=[0,0,1];if(c&&a&&u){const F=ys(_,{filter:J=>!!((J.width||J.initialWidth)&&(J.height||J.initialHeight))}),{x:Y,y:q,zoom:re}=Pc(F,a,u,p,y,(h==null?void 0:h.padding)??.1);$=[Y,q,re]}return{rfId:"1",width:a??0,height:u??0,transform:$,nodes:I,nodesInitialized:A,nodeLookup:_,parentLookup:S,edges:E,edgeLookup:b,connectionLookup:N,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:o!==void 0,hasDefaultEdges:s!==void 0,panZoom:null,minZoom:p,maxZoom:y,translateExtent:as,nodeExtent:j,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:ti.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:w,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:c??!1,fitViewOptions:h,fitViewResolver:null,connection:{...fg},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:sk,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:dg,zIndexMode:g,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},ak=({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p,maxZoom:y,nodeOrigin:x,nodeExtent:v,zIndexMode:g})=>x_((_,S)=>{async function N(){const{nodeLookup:b,panZoom:E,fitViewOptions:I,fitViewResolver:w,width:j,height:A,minZoom:$,maxZoom:F}=S();E&&(await g1({nodes:b,width:j,height:A,panZoom:E,minZoom:$,maxZoom:F},I),w==null||w.resolve(!0),_({fitViewResolver:null}))}return{...vp({nodes:t,edges:r,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p,maxZoom:y,nodeOrigin:x,nodeExtent:v,defaultNodes:o,defaultEdges:s,zIndexMode:g}),setNodes:b=>{const{nodeLookup:E,parentLookup:I,nodeOrigin:w,nodeExtent:j,elevateNodesOnSelect:A,fitViewQueued:$,zIndexMode:F,nodesSelectionActive:Y}=S(),{nodesInitialized:q,hasSelectedNodes:re}=mc(b,E,I,{nodeOrigin:w,nodeExtent:j,elevateNodesOnSelect:A,checkEquality:!0,zIndexMode:F}),J=Y&&re;$&&q?(N(),_({nodes:b,nodesInitialized:q,fitViewQueued:!1,fitViewOptions:void 0,nodesSelectionActive:J})):_({nodes:b,nodesInitialized:q,nodesSelectionActive:J})},setEdges:b=>{const{connectionLookup:E,edgeLookup:I}=S();Ig(E,I,b),_({edges:b})},setDefaultNodesAndEdges:(b,E)=>{if(b){const{setNodes:I}=S();I(b),_({hasDefaultNodes:!0})}if(E){const{setEdges:I}=S();I(E),_({hasDefaultEdges:!0})}},updateNodeInternals:b=>{const{triggerNodeChanges:E,nodeLookup:I,parentLookup:w,domNode:j,nodeOrigin:A,nodeExtent:$,debug:F,fitViewQueued:Y,zIndexMode:q}=S(),{changes:re,updatedInternals:J}=D1(b,I,w,j,A,$,q);J&&(L1(I,w,{nodeOrigin:A,nodeExtent:$,zIndexMode:q}),Y?(N(),_({fitViewQueued:!1,fitViewOptions:void 0})):_({}),(re==null?void 0:re.length)>0&&(F&&console.log("React Flow: trigger node changes",re),E==null||E(re)))},updateNodePositions:(b,E=!1)=>{const I=[];let w=[];const{nodeLookup:j,triggerNodeChanges:A,connection:$,updateConnection:F,onNodesChangeMiddlewareMap:Y}=S();for(const[q,re]of b){const J=j.get(q),te=!!(J!=null&&J.expandParent&&(J!=null&&J.parentId)&&(re!=null&&re.position)),Q={id:q,type:"position",position:te?{x:Math.max(0,re.position.x),y:Math.max(0,re.position.y)}:re.position,dragging:E};if(J&&$.inProgress&&$.fromNode.id===J.id){const C=mo(J,$.fromHandle,ke.Left,!0);F({...$,from:C})}te&&J.parentId&&I.push({id:q,parentId:J.parentId,rect:{...re.internals.positionAbsolute,width:re.measured.width??0,height:re.measured.height??0}}),w.push(Q)}if(I.length>0){const{parentLookup:q,nodeOrigin:re}=S(),J=$c(I,j,q,re);w.push(...J)}for(const q of Y.values())w=q(w);A(w)},triggerNodeChanges:b=>{const{onNodesChange:E,setNodes:I,nodes:w,hasDefaultNodes:j,debug:A}=S();if(b!=null&&b.length){if(j){const $=F_(b,w);I($)}A&&console.log("React Flow: trigger node changes",b),E==null||E(b)}},triggerEdgeChanges:b=>{const{onEdgesChange:E,setEdges:I,edges:w,hasDefaultEdges:j,debug:A}=S();if(b!=null&&b.length){if(j){const $=H_(b,w);I($)}A&&console.log("React Flow: trigger edge changes",b),E==null||E(b)}},addSelectedNodes:b=>{const{multiSelectionActive:E,edgeLookup:I,nodeLookup:w,triggerNodeChanges:j,triggerEdgeChanges:A}=S();if(E){const $=b.map(F=>ao(F,!0));j($);return}j(Ko(w,new Set([...b]),!0)),A(Ko(I))},addSelectedEdges:b=>{const{multiSelectionActive:E,edgeLookup:I,nodeLookup:w,triggerNodeChanges:j,triggerEdgeChanges:A}=S();if(E){const $=b.map(F=>ao(F,!0));A($);return}A(Ko(I,new Set([...b]))),j(Ko(w,new Set,!0))},unselectNodesAndEdges:({nodes:b,edges:E}={})=>{const{edges:I,nodes:w,nodeLookup:j,triggerNodeChanges:A,triggerEdgeChanges:$}=S(),F=b||w,Y=E||I,q=[];for(const J of F){if(!J.selected)continue;const te=j.get(J.id);te&&(te.selected=!1),q.push(ao(J.id,!1))}const re=[];for(const J of Y)J.selected&&re.push(ao(J.id,!1));A(q),$(re)},setMinZoom:b=>{const{panZoom:E,maxZoom:I}=S();E==null||E.setScaleExtent([b,I]),_({minZoom:b})},setMaxZoom:b=>{const{panZoom:E,minZoom:I}=S();E==null||E.setScaleExtent([I,b]),_({maxZoom:b})},setTranslateExtent:b=>{var E;(E=S().panZoom)==null||E.setTranslateExtent(b),_({translateExtent:b})},resetSelectedElements:()=>{const{edges:b,nodes:E,triggerNodeChanges:I,triggerEdgeChanges:w,elementsSelectable:j}=S();if(!j)return;const A=E.reduce((F,Y)=>Y.selected?[...F,ao(Y.id,!1)]:F,[]),$=b.reduce((F,Y)=>Y.selected?[...F,ao(Y.id,!1)]:F,[]);I(A),w($)},setNodeExtent:b=>{const{nodes:E,nodeLookup:I,parentLookup:w,nodeOrigin:j,elevateNodesOnSelect:A,nodeExtent:$,zIndexMode:F}=S();b[0][0]===$[0][0]&&b[0][1]===$[0][1]&&b[1][0]===$[1][0]&&b[1][1]===$[1][1]||(mc(E,I,w,{nodeOrigin:j,nodeExtent:b,elevateNodesOnSelect:A,checkEquality:!1,zIndexMode:F}),_({nodeExtent:b}))},panBy:b=>{const{transform:E,width:I,height:w,panZoom:j,translateExtent:A}=S();return O1({delta:b,panZoom:j,transform:E,translateExtent:A,width:I,height:w})},setCenter:async(b,E,I)=>{const{width:w,height:j,maxZoom:A,panZoom:$}=S();if(!$)return!1;const F=typeof(I==null?void 0:I.zoom)<"u"?I.zoom:A;return await $.setViewport({x:w/2-b*F,y:j/2-E*F,zoom:F},{duration:I==null?void 0:I.duration,ease:I==null?void 0:I.ease,interpolate:I==null?void 0:I.interpolate}),!0},cancelConnection:()=>{_({connection:{...fg}})},updateConnection:b=>{_({connection:b})},reset:()=>_({...vp()})}},Object.is);function vm({initialNodes:t,initialEdges:r,defaultNodes:o,defaultEdges:s,initialWidth:a,initialHeight:u,initialMinZoom:c,initialMaxZoom:h,initialFitViewOptions:p,fitView:y,nodeOrigin:x,nodeExtent:v,zIndexMode:g,children:_}){const[S]=L.useState(()=>ak({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:y,minZoom:c,maxZoom:h,fitViewOptions:p,nodeOrigin:x,nodeExtent:v,zIndexMode:g}));return d.jsx(w_,{value:S,children:d.jsx(G_,{children:d.jsx(aS,{children:_})})})}function lk({children:t,nodes:r,edges:o,defaultNodes:s,defaultEdges:a,width:u,height:c,fitView:h,fitViewOptions:p,minZoom:y,maxZoom:x,nodeOrigin:v,nodeExtent:g,zIndexMode:_}){return L.useContext(sl)?d.jsx(d.Fragment,{children:t}):d.jsx(vm,{initialNodes:r,initialEdges:o,defaultNodes:s,defaultEdges:a,initialWidth:u,initialHeight:c,fitView:h,initialFitViewOptions:p,initialMinZoom:y,initialMaxZoom:x,nodeOrigin:v,nodeExtent:g,zIndexMode:_,children:t})}const uk={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function ck({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,className:a,nodeTypes:u,edgeTypes:c,onNodeClick:h,onEdgeClick:p,onInit:y,onMove:x,onMoveStart:v,onMoveEnd:g,onConnect:_,onConnectStart:S,onConnectEnd:N,onClickConnectStart:b,onClickConnectEnd:E,onNodeMouseEnter:I,onNodeMouseMove:w,onNodeMouseLeave:j,onNodeContextMenu:A,onNodeDoubleClick:$,onNodeDragStart:F,onNodeDrag:Y,onNodeDragStop:q,onNodesDelete:re,onEdgesDelete:J,onDelete:te,onSelectionChange:Q,onSelectionDragStart:C,onSelectionDrag:V,onSelectionDragStop:W,onSelectionContextMenu:U,onSelectionStart:M,onSelectionEnd:D,onBeforeDelete:H,connectionMode:R,connectionLineType:z=$r.Bezier,connectionLineStyle:ne,connectionLineComponent:oe,connectionLineContainerStyle:fe,deleteKeyCode:he="Backspace",selectionKeyCode:pe="Shift",selectionOnDrag:Z=!1,selectionMode:se=ls.Full,panActivationKeyCode:me="Space",multiSelectionKeyCode:Ne=ds()?"Meta":"Control",zoomActivationKeyCode:we=ds()?"Meta":"Control",snapToGrid:ve,snapGrid:Pe,onlyRenderVisibleElements:ue=!1,selectNodesOnDrag:je,nodesDraggable:Le,autoPanOnNodeFocus:nt,nodesConnectable:lt,nodesFocusable:ut,nodeOrigin:Ye=Wg,edgesFocusable:wt,edgesReconnectable:Yt,elementsSelectable:gt=!0,defaultViewport:mt=T_,minZoom:Ct=.5,maxZoom:ct=2,translateExtent:et=as,preventScrolling:On=!0,nodeExtent:Mt,defaultMarkerColor:kn="#b1b1b7",zoomOnScroll:ui=!0,zoomOnPinch:Fn=!0,panOnScroll:vo=!1,panOnScrollSpeed:lr=.5,panOnScrollMode:Or=co.Free,zoomOnDoubleClick:Hn=!0,panOnDrag:Fr=!0,onPaneClick:ur,onPaneMouseEnter:cr,onPaneMouseMove:Ft,onPaneMouseLeave:dt,onPaneScroll:Bn,onPaneContextMenu:Vn,paneClickDistance:Nn=1,nodeClickDistance:Wn=0,children:jn,onReconnect:it,onReconnectStart:dr,onReconnectEnd:bn,onEdgeContextMenu:Pt,onEdgeDoubleClick:nn,onEdgeMouseEnter:xo,onEdgeMouseMove:Ze,onEdgeMouseLeave:He,reconnectRadius:En=10,onNodesChange:Un,onEdgesChange:rn,noDragClassName:Hr="nodrag",noWheelClassName:on="nowheel",noPanClassName:It="nopan",fitView:Xt,fitViewOptions:Gn,connectOnClick:wo,attributionPosition:_o,proOptions:Rt,defaultEdgeOptions:Yn,elevateNodesOnSelect:Br=!0,elevateEdgesOnSelect:Xn=!1,disableKeyboardA11y:fr=!1,autoPanOnConnect:Ve,autoPanOnNodeDrag:ci,autoPanOnSelection:Vr=!0,autoPanSpeed:So,connectionRadius:hr,isValidConnection:di,onError:ko,style:Cn,id:_t,nodeDragThreshold:fi,connectionDragThreshold:yt,viewport:hi,onViewportChange:pi,width:Wr,height:Mn,colorMode:qn="light",debug:Pn,onScroll:qt,ariaLabelConfig:Ur,zIndexMode:Gr="basic",...pr},Yr){const sn=_t||"1",Kn=z_(qn),No=L.useCallback(gr=>{gr.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),qt==null||qt(gr)},[qt]);return d.jsx("div",{"data-testid":"rf__wrapper",...pr,onScroll:No,style:{...Cn,...uk},ref:Yr,className:ot(["react-flow",a,Kn]),id:_t,role:"application",children:d.jsxs(lk,{nodes:t,edges:r,width:Wr,height:Mn,fitView:Xt,fitViewOptions:Gn,minZoom:Ct,maxZoom:ct,nodeOrigin:Ye,nodeExtent:Mt,zIndexMode:Gr,children:[d.jsx($_,{nodes:t,edges:r,defaultNodes:o,defaultEdges:s,onConnect:_,onConnectStart:S,onConnectEnd:N,onClickConnectStart:b,onClickConnectEnd:E,nodesDraggable:Le,autoPanOnNodeFocus:nt,nodesConnectable:lt,nodesFocusable:ut,edgesFocusable:wt,edgesReconnectable:Yt,elementsSelectable:gt,elevateNodesOnSelect:Br,elevateEdgesOnSelect:Xn,minZoom:Ct,maxZoom:ct,nodeExtent:Mt,onNodesChange:Un,onEdgesChange:rn,snapToGrid:ve,snapGrid:Pe,connectionMode:R,translateExtent:et,connectOnClick:wo,defaultEdgeOptions:Yn,fitView:Xt,fitViewOptions:Gn,onNodesDelete:re,onEdgesDelete:J,onDelete:te,onNodeDragStart:F,onNodeDrag:Y,onNodeDragStop:q,onSelectionDrag:V,onSelectionDragStart:C,onSelectionDragStop:W,onMove:x,onMoveStart:v,onMoveEnd:g,noPanClassName:It,nodeOrigin:Ye,rfId:sn,autoPanOnConnect:Ve,autoPanOnNodeDrag:ci,autoPanSpeed:So,onError:ko,connectionRadius:hr,isValidConnection:di,selectNodesOnDrag:je,nodeDragThreshold:fi,connectionDragThreshold:yt,onBeforeDelete:H,debug:Pn,ariaLabelConfig:Ur,zIndexMode:Gr}),d.jsx(ik,{onInit:y,onNodeClick:h,onEdgeClick:p,onNodeMouseEnter:I,onNodeMouseMove:w,onNodeMouseLeave:j,onNodeContextMenu:A,onNodeDoubleClick:$,nodeTypes:u,edgeTypes:c,connectionLineType:z,connectionLineStyle:ne,connectionLineComponent:oe,connectionLineContainerStyle:fe,selectionKeyCode:pe,selectionOnDrag:Z,selectionMode:se,deleteKeyCode:he,multiSelectionKeyCode:Ne,panActivationKeyCode:me,zoomActivationKeyCode:we,onlyRenderVisibleElements:ue,defaultViewport:mt,translateExtent:et,minZoom:Ct,maxZoom:ct,preventScrolling:On,zoomOnScroll:ui,zoomOnPinch:Fn,zoomOnDoubleClick:Hn,panOnScroll:vo,panOnScrollSpeed:lr,panOnScrollMode:Or,panOnDrag:Fr,autoPanOnSelection:Vr,onPaneClick:ur,onPaneMouseEnter:cr,onPaneMouseMove:Ft,onPaneMouseLeave:dt,onPaneScroll:Bn,onPaneContextMenu:Vn,paneClickDistance:Nn,nodeClickDistance:Wn,onSelectionContextMenu:U,onSelectionStart:M,onSelectionEnd:D,onReconnect:it,onReconnectStart:dr,onReconnectEnd:bn,onEdgeContextMenu:Pt,onEdgeDoubleClick:nn,onEdgeMouseEnter:xo,onEdgeMouseMove:Ze,onEdgeMouseLeave:He,reconnectRadius:En,defaultMarkerColor:kn,noDragClassName:Hr,noWheelClassName:on,noPanClassName:It,rfId:sn,disableKeyboardA11y:fr,nodeExtent:Mt,viewport:hi,onViewportChange:pi,nodesDraggable:Le}),d.jsx(R_,{onSelectionChange:Q}),jn,d.jsx(E_,{proOptions:Rt,position:_o}),d.jsx(b_,{rfId:sn,disableKeyboardA11y:fr})]})})}var dk=Gg(ck);function fk({dimensions:t,lineWidth:r,variant:o,className:s}){return d.jsx("path",{strokeWidth:r,d:`M${t[0]/2} 0 V${t[1]} M0 ${t[1]/2} H${t[0]}`,className:ot(["react-flow__background-pattern",o,s])})}function hk({radius:t,className:r}){return d.jsx("circle",{cx:t,cy:t,r:t,className:ot(["react-flow__background-pattern","dots",r])})}var zr;(function(t){t.Lines="lines",t.Dots="dots",t.Cross="cross"})(zr||(zr={}));const pk={[zr.Dots]:1,[zr.Lines]:1,[zr.Cross]:6},gk=t=>({transform:t.transform,patternId:`pattern-${t.rfId}`});function xm({id:t,variant:r=zr.Dots,gap:o=20,size:s,lineWidth:a=1,offset:u=0,color:c,bgColor:h,style:p,className:y,patternClassName:x}){const v=L.useRef(null),{transform:g,patternId:_}=De(gk,Qe),S=s||pk[r],N=r===zr.Dots,b=r===zr.Cross,E=Array.isArray(o)?o:[o,o],I=[E[0]*g[2]||1,E[1]*g[2]||1],w=S*g[2],j=Array.isArray(u)?u:[u,u],A=b?[w,w]:I,$=[j[0]*g[2]+A[0]/2,j[1]*g[2]+A[1]/2],F=`${_}${t||""}`;return d.jsxs("svg",{className:ot(["react-flow__background",y]),style:{...p,...ul,"--xy-background-color-props":h,"--xy-background-pattern-color-props":c},ref:v,"data-testid":"rf__background",children:[d.jsx("pattern",{id:F,x:g[0]%I[0],y:g[1]%I[1],width:I[0],height:I[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${$[0]},-${$[1]})`,children:N?d.jsx(hk,{radius:w/2,className:x}):d.jsx(fk,{dimensions:A,lineWidth:a,variant:r,className:x})}),d.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${F})`})]})}xm.displayName="Background";const mk=L.memo(xm);function yk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:d.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function vk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:d.jsx("path",{d:"M0 0h32v4.2H0z"})})}function xk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:d.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function wk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function _k(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function Pa({children:t,className:r,...o}){return d.jsx("button",{type:"button",className:ot(["react-flow__controls-button",r]),...o,children:t})}const Sk=t=>({isInteractive:t.nodesDraggable||t.nodesConnectable||t.elementsSelectable,minZoomReached:t.transform[2]<=t.minZoom,maxZoomReached:t.transform[2]>=t.maxZoom,ariaLabelConfig:t.ariaLabelConfig});function wm({style:t,showZoom:r=!0,showFitView:o=!0,showInteractive:s=!0,fitViewOptions:a,onZoomIn:u,onZoomOut:c,onFitView:h,onInteractiveChange:p,className:y,children:x,position:v="bottom-left",orientation:g="vertical","aria-label":_}){const S=Ge(),{isInteractive:N,minZoomReached:b,maxZoomReached:E,ariaLabelConfig:I}=De(Sk,Qe),{zoomIn:w,zoomOut:j,fitView:A}=ll(),$=()=>{w(),u==null||u()},F=()=>{j(),c==null||c()},Y=()=>{A(a),h==null||h()},q=()=>{S.setState({nodesDraggable:!N,nodesConnectable:!N,elementsSelectable:!N}),p==null||p(!N)},re=g==="horizontal"?"horizontal":"vertical";return d.jsxs(al,{className:ot(["react-flow__controls",re,y]),position:v,style:t,"data-testid":"rf__controls","aria-label":_??I["controls.ariaLabel"],children:[r&&d.jsxs(d.Fragment,{children:[d.jsx(Pa,{onClick:$,className:"react-flow__controls-zoomin",title:I["controls.zoomIn.ariaLabel"],"aria-label":I["controls.zoomIn.ariaLabel"],disabled:E,children:d.jsx(yk,{})}),d.jsx(Pa,{onClick:F,className:"react-flow__controls-zoomout",title:I["controls.zoomOut.ariaLabel"],"aria-label":I["controls.zoomOut.ariaLabel"],disabled:b,children:d.jsx(vk,{})})]}),o&&d.jsx(Pa,{className:"react-flow__controls-fitview",onClick:Y,title:I["controls.fitView.ariaLabel"],"aria-label":I["controls.fitView.ariaLabel"],children:d.jsx(xk,{})}),s&&d.jsx(Pa,{className:"react-flow__controls-interactive",onClick:q,title:I["controls.interactive.ariaLabel"],"aria-label":I["controls.interactive.ariaLabel"],children:N?d.jsx(_k,{}):d.jsx(wk,{})}),x]})}wm.displayName="Controls";const kk=L.memo(wm);function Nk({id:t,x:r,y:o,width:s,height:a,style:u,color:c,strokeColor:h,strokeWidth:p,className:y,borderRadius:x,shapeRendering:v,selected:g,onClick:_}){const{background:S,backgroundColor:N}=u||{},b=c||S||N;return d.jsx("rect",{className:ot(["react-flow__minimap-node",{selected:g},y]),x:r,y:o,rx:x,ry:x,width:s,height:a,style:{fill:b,stroke:h,strokeWidth:p},shapeRendering:v,onClick:_?E=>_(E,t):void 0})}const jk=L.memo(Nk),bk=t=>t.nodes.map(r=>r.id),tc=t=>t instanceof Function?t:()=>t;function Ek({nodeStrokeColor:t,nodeColor:r,nodeClassName:o="",nodeBorderRadius:s=5,nodeStrokeWidth:a,nodeComponent:u=jk,onClick:c}){const h=De(bk,Qe),p=tc(r),y=tc(t),x=tc(o),v=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return d.jsx(d.Fragment,{children:h.map(g=>d.jsx(Mk,{id:g,nodeColorFunc:p,nodeStrokeColorFunc:y,nodeClassNameFunc:x,nodeBorderRadius:s,nodeStrokeWidth:a,NodeComponent:u,onClick:c,shapeRendering:v},g))})}function Ck({id:t,nodeColorFunc:r,nodeStrokeColorFunc:o,nodeClassNameFunc:s,nodeBorderRadius:a,nodeStrokeWidth:u,shapeRendering:c,NodeComponent:h,onClick:p}){const{node:y,x,y:v,width:g,height:_}=De(S=>{const N=S.nodeLookup.get(t);if(!N)return{node:void 0,x:0,y:0,width:0,height:0};const b=N.internals.userNode,{x:E,y:I}=N.internals.positionAbsolute,{width:w,height:j}=Sn(b);return{node:b,x:E,y:I,width:w,height:j}},Qe);return!y||y.hidden||!wg(y)?null:d.jsx(h,{x,y:v,width:g,height:_,style:y.style,selected:!!y.selected,className:s(y),color:r(y),borderRadius:a,strokeColor:o(y),strokeWidth:u,shapeRendering:c,onClick:p,id:y.id})}const Mk=L.memo(Ck);var Pk=L.memo(Ek);const Ik=200,Rk=150,Tk=t=>!t.hidden,Lk=t=>{const r={x:-t.transform[0]/t.transform[2],y:-t.transform[1]/t.transform[2],width:t.width/t.transform[2],height:t.height/t.transform[2]};return{viewBB:r,boundingRect:t.nodeLookup.size>0?yg(ys(t.nodeLookup,{filter:Tk}),r):r,rfId:t.rfId,panZoom:t.panZoom,translateExtent:t.translateExtent,flowWidth:t.width,flowHeight:t.height,ariaLabelConfig:t.ariaLabelConfig}},xp=(t,r)=>t.x===r.x&&t.y===r.y&&t.width===r.width&&t.height===r.height,Ak=(t,r)=>xp(t.viewBB,r.viewBB)&&xp(t.boundingRect,r.boundingRect)&&t.rfId===r.rfId&&t.panZoom===r.panZoom&&t.translateExtent===r.translateExtent&&t.flowWidth===r.flowWidth&&t.flowHeight===r.flowHeight&&t.ariaLabelConfig===r.ariaLabelConfig,$k="react-flow__minimap-desc";function _m({style:t,className:r,nodeStrokeColor:o,nodeColor:s,nodeClassName:a="",nodeBorderRadius:u=5,nodeStrokeWidth:c,nodeComponent:h,bgColor:p,maskColor:y,maskStrokeColor:x,maskStrokeWidth:v,position:g="bottom-right",onClick:_,onNodeClick:S,pannable:N=!1,zoomable:b=!1,ariaLabel:E,inversePan:I,zoomStep:w=1,offsetScale:j=5}){const A=Ge(),$=L.useRef(null),{boundingRect:F,viewBB:Y,rfId:q,panZoom:re,translateExtent:J,flowWidth:te,flowHeight:Q,ariaLabelConfig:C}=De(Lk,Ak),V=(t==null?void 0:t.width)??Ik,W=(t==null?void 0:t.height)??Rk,U=F.width/V,M=F.height/W,D=Math.max(U,M),H=D*V,R=D*W,z=j*D,ne=F.x-(H-F.width)/2-z,oe=F.y-(R-F.height)/2-z,fe=H+z*2,he=R+z*2,pe=`${$k}-${q}`,Z=L.useRef(0),se=L.useRef();Z.current=D,L.useEffect(()=>{if($.current&&re)return se.current=X1({domNode:$.current,panZoom:re,getTransform:()=>A.getState().transform,getViewScale:()=>Z.current}),()=>{var ve;(ve=se.current)==null||ve.destroy()}},[re]),L.useEffect(()=>{var ve;(ve=se.current)==null||ve.update({translateExtent:J,width:te,height:Q,inversePan:I,pannable:N,zoomStep:w,zoomable:b})},[N,b,I,w,J,te,Q]);const me=_?ve=>{var je;const[Pe,ue]=((je=se.current)==null?void 0:je.pointer(ve))||[0,0];_(ve,{x:Pe,y:ue})}:void 0,Ne=S?L.useCallback((ve,Pe)=>{const ue=A.getState().nodeLookup.get(Pe).internals.userNode;S(ve,ue)},[]):void 0,we=E??C["minimap.ariaLabel"];return d.jsx(al,{position:g,style:{...t,"--xy-minimap-background-color-props":typeof p=="string"?p:void 0,"--xy-minimap-mask-background-color-props":typeof y=="string"?y:void 0,"--xy-minimap-mask-stroke-color-props":typeof x=="string"?x:void 0,"--xy-minimap-mask-stroke-width-props":typeof v=="number"?v*D:void 0,"--xy-minimap-node-background-color-props":typeof s=="string"?s:void 0,"--xy-minimap-node-stroke-color-props":typeof o=="string"?o:void 0,"--xy-minimap-node-stroke-width-props":typeof c=="number"?c:void 0},className:ot(["react-flow__minimap",r]),"data-testid":"rf__minimap",children:d.jsxs("svg",{width:V,height:W,viewBox:`${ne} ${oe} ${fe} ${he}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":pe,ref:$,onClick:me,children:[we&&d.jsx("title",{id:pe,children:we}),d.jsx(Pk,{onClick:Ne,nodeColor:s,nodeStrokeColor:o,nodeBorderRadius:u,nodeClassName:a,nodeStrokeWidth:c,nodeComponent:h}),d.jsx("path",{className:"react-flow__minimap-mask",d:`M${ne-z},${oe-z}h${fe+z*2}v${he+z*2}h${-fe-z*2}z - M${Y.x},${Y.y}h${Y.width}v${Y.height}h${-Y.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}_m.displayName="MiniMap";const zk=L.memo(_m),Dk=t=>r=>t?`${Math.max(1/r.transform[2],1)}`:void 0,Ok={[oi.Line]:"right",[oi.Handle]:"bottom-right"};function Fk({nodeId:t,position:r,variant:o=oi.Handle,className:s,style:a=void 0,children:u,color:c,minWidth:h=10,minHeight:p=10,maxWidth:y=Number.MAX_VALUE,maxHeight:x=Number.MAX_VALUE,keepAspectRatio:v=!1,resizeDirection:g,autoScale:_=!0,shouldResize:S,onResizeStart:N,onResize:b,onResizeEnd:E}){const I=Qg(),w=typeof t=="string"?t:I,j=Ge(),A=L.useRef(null),$=o===oi.Handle,F=De(L.useCallback(Dk($&&_),[$,_]),Qe),Y=L.useRef(null),q=r??Ok[o];L.useEffect(()=>{if(!(!A.current||!w))return Y.current||(Y.current=a_({domNode:A.current,nodeId:w,getStoreItems:()=>{const{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,domNode:W}=j.getState();return{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,paneDomNode:W}},onChange:(J,te)=>{const{triggerNodeChanges:Q,nodeLookup:C,parentLookup:V,nodeOrigin:W}=j.getState(),U=[],M={x:J.x,y:J.y},D=C.get(w);if(D&&D.expandParent&&D.parentId){const H=D.origin??W,R=J.width??D.measured.width??0,z=J.height??D.measured.height??0,ne={id:D.id,parentId:D.parentId,rect:{width:R,height:z,..._g({x:J.x??D.position.x,y:J.y??D.position.y},{width:R,height:z},D.parentId,C,H)}},oe=$c([ne],C,V,W);U.push(...oe),M.x=J.x?Math.max(H[0]*R,J.x):void 0,M.y=J.y?Math.max(H[1]*z,J.y):void 0}if(M.x!==void 0&&M.y!==void 0){const H={id:w,type:"position",position:{...M}};U.push(H)}if(J.width!==void 0&&J.height!==void 0){const R={id:w,type:"dimensions",resizing:!0,setAttributes:g?g==="horizontal"?"width":"height":!0,dimensions:{width:J.width,height:J.height}};U.push(R)}for(const H of te){const R={...H,type:"position"};U.push(R)}Q(U)},onEnd:({width:J,height:te})=>{const Q={id:w,type:"dimensions",resizing:!1,dimensions:{width:J,height:te}};j.getState().triggerNodeChanges([Q])}})),Y.current.update({controlPosition:q,boundaries:{minWidth:h,minHeight:p,maxWidth:y,maxHeight:x},keepAspectRatio:v,resizeDirection:g,onResizeStart:N,onResize:b,onResizeEnd:E,shouldResize:S}),()=>{var J;(J=Y.current)==null||J.destroy()}},[q,h,p,y,x,v,N,b,E,S]);const re=q.split("-");return d.jsx("div",{className:ot(["react-flow__resize-control","nodrag",...re,o,s]),ref:A,style:{...a,scale:F,...c&&{[$?"backgroundColor":"borderColor"]:c}},children:u})}L.memo(Fk);const Hk={"arch.context":0,"django.app":0,"django.route":1,"django.websocket_route":1,"fastapi.route":1,"django.url_name":2,"django.view":3,"django.viewset_action":3,"django.permission":3,"django.throttle":3,"django.serializer":4,"django.form":4,"graphql.type":4,"fastapi.model":4,"django.serializer_field":5,"django.service":5,"graphql.field":5,"django.model":6,"django.field":7,"django.relation":7,"django.task":8,"django.receiver":8,"django.signal":8,"django.test":8,"django.migration_op":8,"django.admin":8,"django.management_command":8,"django.consumer":8,"django.cache_key":8,"django.feature_flag":8,"django.side_effect":8,"openapi.path":9,"graphql.operation":9,"react.api_client":10,"django.htmx":10,"react.query_key":11,"react.hook":11,"react.feature":11,"react.route":12,"react.page":12,"react.server_action":12,"django.template":12,"react.component":13,"react.context":13,"react.form_schema":14,"react.test":14};function si(t){return Hk[t]??8}const zn=208,Dr=64,ai=88,Dc=28,Bk=8;function Vk(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function Sm(t,r=[]){const o=new Map;if(!t.length)return o;const s=new Map;for(const w of t){const j=si(w.type),A=s.get(j)??[];A.push(w),s.set(j,A)}const u=[...s.keys()].sort((w,j)=>w-j).map(w=>[...s.get(w)??[]].sort((j,A)=>j.name.localeCompare(A.name)||j.id.localeCompare(A.id))),c=new Set(t.map(w=>w.id)),h=new Map,p=new Map;for(const w of t)h.set(w.id,[]),p.set(w.id,[]);for(const w of r)!c.has(w.src)||!c.has(w.dst)||w.src===w.dst||(p.get(w.src).push(w.dst),h.get(w.dst).push(w.src));const y=new Map;u.forEach((w,j)=>{for(const A of w)y.set(A.id,j)});const x=new Map,v=()=>{for(const w of u)w.forEach((j,A)=>x.set(j.id,A))};v();const g=(w,j)=>{const A=w.map(($,F)=>{const Y=j($.id).map(re=>x.get(re)).filter(re=>re!==void 0),q=Vk(Y);return{n:$,bary:Number.isNaN(q)?F:q,name:$.name,id:$.id}});return A.sort(($,F)=>$.bary-F.bary||$.name.localeCompare(F.name)||$.id.localeCompare(F.id)),A.map($=>$.n)},_=w=>j=>y.get(j)===w;for(let w=0;w(h.get(A)??[]).filter(_(j-1))),v();for(let j=u.length-2;j>=0;j--)u[j]=g(u[j],A=>(p.get(A)??[]).filter(_(j+1))),v()}const S=zn+ai,N=Dr+Dc,b=Math.max(...u.map(w=>w.length),1),E=[];let I=0;for(let w=0;wY.id)),A=new Set((u[w+1]??[]).map(Y=>Y.id));let $=0;if(A.size)for(const Y of r)j.has(Y.src)&&A.has(Y.dst)&&($+=1);const F=Math.min(120,Math.max(0,($-2)*12));I+=S+F}return u.forEach((w,j)=>{const A=(b-w.length)*N/2;w.forEach(($,F)=>{o.set($.id,{x:E[j]??0,y:A+F*N})})}),o}const xc=[{id:"layers",label:"Architecture layers"},{id:"flow",label:"Edge flow"},{id:"radial",label:"Radial"},{id:"grid",label:"Compact grid"}],Wk=new Set(xc.map(t=>t.id)),km="loadpath.graphLayout",Uk=8,Gk=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","openapi.path","django.consumer","django.websocket_route","django.template","graphql.operation","fastapi.route"]),Nm=90,Yk=new Set(["django.field","django.serializer_field","django.relation","django.test","react.test","graphql.field","django.url_name","django.throttle"]),wp={"arch.context":"#edf2f4","django.app":"#8d99ae","django.route":"#4cc9f0","django.url_name":"#4cc9f0","django.view":"#4895ef","django.viewset_action":"#4361ee","django.permission":"#7b8cde","django.serializer":"#f4a261","django.form":"#e9c46a","django.serializer_field":"#e9c46a","django.service":"#90be6d","django.model":"#2a9d8f","django.field":"#8ac926","django.task":"#e76f51","django.receiver":"#e85d04","django.signal":"#f4a261","django.test":"#6c757d","django.admin":"#adb5bd","django.migration_op":"#9d4edd","django.consumer":"#e76f51","django.websocket_route":"#4cc9f0","django.template":"#c77dff","django.htmx":"#ff6b6b","django.cache_key":"#6c757d","django.feature_flag":"#f4a261","django.side_effect":"#e85d04","graphql.type":"#00bbf9","graphql.operation":"#00bbf9","fastapi.route":"#4cc9f0","fastapi.model":"#f4a261","openapi.path":"#00bbf9","react.api_client":"#ff6b6b","react.query_key":"#adb5bd","react.hook":"#7b2cbf","react.feature":"#9d4edd","react.route":"#c77dff","react.page":"#c77dff","react.server_action":"#e76f51","react.component":"#9d4edd","react.form_schema":"#ffd166","react.test":"#6c757d"},Xk=Math.PI*(3-Math.sqrt(5)),jm=220,qk=26,Kk={0:"context",1:"routes",2:"url names",3:"views",4:"serializers",5:"services",6:"models",7:"fields",8:"jobs / signals",9:"openapi",10:"api client",11:"hooks",12:"pages",13:"components",14:"forms / tests"};function bm(t){return t.startsWith("react.")?"react":t.startsWith("openapi.")||t.startsWith("graphql.")||t.startsWith("fastapi.")?"stitch":t.startsWith("arch.")?"arch":"django"}function aj(t){return wp[t]?wp[t]:t.startsWith("react.")?"#9d4edd":t.startsWith("openapi.")?"#00bbf9":"#4a5568"}function Qk(t){return t>=Nm?"3d":"2d"}function Zk(t){return t>=Nm?"overview":"full"}function Jk(t,r,o=1){const s=new Set([t]);let a=new Set([t]);for(let u=0;uo.families.has(bm(h.type)));o.detail==="overview"&&(s=s.filter(h=>!Yk.has(h.type)));const a=new Set(s.map(h=>h.id)),u=r.filter(h=>a.has(h.src)&&a.has(h.dst)),c=o.focusId?Jk(o.focusId,u,1):new Set;if(o.neighborhoodOnly&&o.focusId&&c.size){s=s.filter(p=>c.has(p.id));const h=new Set(s.map(p=>p.id));return{nodes:s,edges:u.filter(p=>h.has(p.src)&&h.has(p.dst)),neighborIds:c}}return{nodes:s,edges:u,neighborIds:c}}function tN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>`${s.name} ${s.qualified_name} ${s.type} ${s.file_path||""} ${s.context||""}`.toLowerCase().includes(o)).slice(0,24):[]}function nN(t,r,o,s){const a=new Set(t.map(N=>N.id));if(!a.has(o))return{nodeIds:new Set,edgeIds:new Set};const u=new Map,c=new Map;for(const N of r){if(!a.has(N.src)||!a.has(N.dst))continue;const b=u.get(N.src)??[];b.push({dst:N.dst,id:N.id}),u.set(N.src,b);const E=c.get(N.dst)??[];E.push({src:N.src,id:N.id}),c.set(N.dst,E)}const h=new Set(t.filter(N=>Gk.has(N.type)).map(N=>N.id)),p=h.size?h:a,y=new Set,x=[o];for(;x.length;){const N=x.pop();if(!y.has(N)){y.add(N);for(const b of u.get(N)??[])y.has(b.dst)||x.push(b.dst)}}const v=new Set([o]),g=[...p].filter(N=>y.has(N)),_=new Set(g);for(;g.length;){const N=g.pop();v.add(N);for(const b of c.get(N)??[])y.has(b.src)&&!_.has(b.src)&&(_.add(b.src),g.push(b.src))}const S=new Set;for(const N of r)v.has(N.src)&&v.has(N.dst)&&S.add(N.id);return{nodeIds:v,edgeIds:S}}function lj(t){const r=new Map;for(const s of t){const a=si(s.type),u=r.get(a)??[];u.push(s),r.set(a,u)}const o=new Map;for(const[s,a]of r){a.sort((c,h)=>c.name.localeCompare(h.name));const u=s*jm;a.forEach((c,h)=>{if(a.length===1){o.set(c.id,{x:u,y:0,z:0});return}const p=qk*Math.sqrt(h+1),y=h*Xk;o.set(c.id,{x:u,y:p*Math.cos(y),z:p*Math.sin(y)})})}return o}function uj(t){const r=new Map;for(const o of t){const s=si(o.type);r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>o[0]-s[0]).map(([o,s])=>({layer:o,x:o*jm,count:s}))}function rN(){try{if(typeof localStorage>"u")return"layers";const t=localStorage.getItem(km);return t&&Wk.has(t)?t:"layers"}catch{return"layers"}}function oN(t){try{if(typeof localStorage>"u")return;localStorage.setItem(km,t)}catch{}}function iN(t){return t==="layers"||t==="flow"}function sN(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function ts(t,r){return t.name.localeCompare(r.name)||t.id.localeCompare(r.id)}function aN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.flat().map(S=>S.id)),a=new Map,u=new Map;for(const S of t.flat())a.set(S.id,[]),u.set(S.id,[]);for(const S of r)!s.has(S.src)||!s.has(S.dst)||S.src===S.dst||(u.get(S.src).push(S.dst),a.get(S.dst).push(S.src));const c=new Map;t.forEach((S,N)=>{for(const b of S)c.set(b.id,N)});const h=new Map,p=()=>{for(const S of t)S.forEach((N,b)=>h.set(N.id,b))};p();const y=(S,N)=>{const b=S.map((E,I)=>{const w=N(E.id).map(A=>h.get(A)).filter(A=>A!==void 0),j=sN(w);return{n:E,bary:Number.isNaN(j)?I:j,name:E.name,id:E.id}});return b.sort((E,I)=>E.bary-I.bary||E.name.localeCompare(I.name)||E.id.localeCompare(I.id)),b.map(E=>E.n)},x=S=>N=>c.get(N)===S;for(let S=0;S(a.get(b)??[]).filter(x(N-1))),p();for(let N=t.length-2;N>=0;N--)t[N]=y(t[N],b=>(u.get(b)??[]).filter(x(N+1))),p()}const v=zn+ai,g=Dr+Dc,_=Math.max(...t.map(S=>S.length),1);return t.forEach((S,N)=>{const b=(_-S.length)*g/2;S.forEach((E,I)=>{o.set(E.id,{x:N*v,y:b+I*g})})}),o}function lN(t,r){const o=new Set(t.map(h=>h.id)),s=Math.max(t.length-1,0),a=new Map;for(const h of t)a.set(h.id,0);for(let h=0;h(a.get(y.dst)||0)&&(a.set(y.dst,x),p=!0)}if(!p)break}const u=new Map;for(const h of t){const p=a.get(h.id)||0,y=u.get(p)??[];y.push(h),u.set(p,y)}const c=[...u.keys()].sort((h,p)=>h-p).map(h=>(u.get(h)??[]).sort(ts));return aN(c,r)}function uN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.map(g=>g.id)),a=new Map,u=new Map;for(const g of t)a.set(g.id,[]),u.set(g.id,0);for(const g of r)!s.has(g.src)||!s.has(g.dst)||g.src===g.dst||(a.get(g.src).push(g.dst),a.get(g.dst).push(g.src),u.set(g.src,(u.get(g.src)||0)+1),u.set(g.dst,(u.get(g.dst)||0)+1));const c=[...t].sort((g,_)=>(u.get(_.id)||0)-(u.get(g.id)||0)||ts(g,_))[0]??t[0],h=new Map,p=[[c]];h.set(c.id,0);const y=[c];for(;y.length;){const g=y.shift(),_=h.get(g.id)||0,S=(a.get(g.id)??[]).map(N=>t.find(b=>b.id===N)).filter(N=>!!N).sort(ts);for(const N of S){if(h.has(N.id))continue;h.set(N.id,_+1);const b=p[_+1]??[];b.push(N),p[_+1]=b,y.push(N)}}const x=t.filter(g=>!h.has(g.id)).sort(ts);x.length&&p.push(x);const v=zn+32;return p.forEach((g,_)=>{if(_===0&&g.length===1){o.set(g[0].id,{x:0,y:0});return}const S=Math.max(_*(zn+ai),g.length<=1?zn:g.length*v/(2*Math.PI));g.forEach((N,b)=>{const E=-Math.PI/2+2*Math.PI*b/g.length;o.set(N.id,{x:Math.cos(E)*S,y:Math.sin(E)*S})})}),o}function cN(t){const r=new Map,o=[...t].sort((c,h)=>si(c.type)-si(h.type)||ts(c,h)),s=Math.max(1,Math.ceil(Math.sqrt(o.length))),a=zn+ai,u=Dr+Dc;return o.forEach((c,h)=>{r.set(c.id,{x:h%s*a,y:Math.floor(h/s)*u})}),r}function dN(t,r=[],o="layers"){return o==="flow"?lN(t,r):o==="radial"?uN(t,r):o==="grid"?cN(t):Sm(t,r)}const Ia=16,fN=12,hN=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","django.throttle","django.admin","django.management_command","openapi.path","django.consumer","django.websocket_route","django.template","django.cache_key","django.feature_flag","django.side_effect","graphql.operation","fastapi.route"]),pN=new Set(["django.serializer","django.serializer_field","django.form","openapi.path","react.form_schema","django.route","graphql.type","graphql.field","graphql.operation","fastapi.model","fastapi.route"]),_p={"arch.context":"Ownership boundary from loadpath.yml — the context this code belongs to.","django.app":"Django app package that owns models, views, and jobs.","django.route":"HTTP URL that publishes a view. A sink: this is where a change becomes a public request.","django.url_name":"Named URL used by reverse() / {% url %} lookups.","django.view":"Request handler (class-based view, function view, or ViewSet).","django.viewset_action":"One ViewSet action (list, create, retrieve, update, destroy).","django.permission":"Auth gate on a view — who is allowed to hit this path.","django.throttle":"Rate-limit class attached to a view.","django.serializer":"Request/response contract: which fields go in and come out.","django.form":"Django form or django-filter FilterSet — the typed input contract.","django.serializer_field":"One field on a serializer or form — the typed slot on the contract.","django.service":"Internal service or use-case. Work that is not itself an HTTP sink.","django.model":"ORM model. Schema and relations live here.","django.field":"Model column. Type, indexes, and relations are the contract of the table.","django.relation":"Model-to-model relation (FK / M2M / O2O).","django.task":"Celery or Dramatiq job. Once enqueued, this is a sink.","django.receiver":"Signal handler that runs after a model event.","django.signal":"Django signal that receivers subscribe to.","django.test":"Backend test that mentions symbols on this path.","django.admin":"Django admin class for a model.","django.migration_op":"Schema migration operation (CreateModel, AlterField, …).","django.management_command":"manage.py command — an operational sink.","django.consumer":"Django Channels WebSocket/HTTP consumer. A sink once a client connects.","django.websocket_route":"ASGI WebSocket URL. A sink: this is where a change becomes a live connection.","django.template":"Django template. HTML (and HTMX) the server renders.","django.htmx":"HTMX call from a template to a URL — another published seam.","django.cache_key":"Cache get/set key. Invalidation is part of the load path.","django.feature_flag":"Feature flag checked on this path. The change may be dark-launched.","django.side_effect":"transaction.on_commit (or similar) side effect that runs after the request commits.","graphql.type":"GraphQL object/input type — a published contract.","graphql.field":"One field on a GraphQL type.","graphql.operation":"GraphQL query, mutation, or subscription. A published contract and a sink.","fastapi.route":"FastAPI path operation sitting next to Django in this repo.","fastapi.model":"Pydantic response/request model — the FastAPI contract.","openapi.path":"Generated OpenAPI operation. The typed HTTP contract between stacks.","react.api_client":"Frontend fetch or generated client call to an API path.","react.query_key":"React Query cache key. Invalidation and reads share this name.","react.hook":"Data hook wrapping query or mutation calls.","react.feature":"Frontend feature module (folder).","react.route":"Client-side route. A sink: this is a URL the user can open.","react.page":"Page or screen component rendered by a route.","react.server_action":"Next.js Server Action. A sink: the mutation runs on the server.","react.component":"UI component.","react.form_schema":"Zod (or similar) schema — typed form inputs on the client.","react.test":"Frontend test covering a page, hook, or component.","react.context":"React context provider."},gN={field_type:"Type",fields:"Fields",form_fields:"Form fields",permissions:"Permissions",throttles:"Throttles",authentication:"Authentication",pagination:"Pagination",filterset:"Filterset",bases:"Extends",on_delete:"on_delete",related_name:"related_name",unique:"Unique",db_index:"Indexed",relation:"Relation field",looks_idempotent_on_pk:"Idempotent on pk",broker:"Broker",route:"Route",url_name:"URL name",view:"View",include:"Includes",mounted_at:"Mounted at",full_path:"Full path",method:"Method",path:"Path",operation_id:"Operation",raw:"URL",kind:"Schema",exclude:"Excludes",queryset_in_serializer:"Queryset in serializer",get_queryset:"Custom get_queryset",get_serializer_class:"Dynamic serializer",dynamic:"Dynamic",fbv:"Function view",next_app:"Next.js App Router",next_pages:"Next.js Pages Router",next_kind:"Next file",next_layout:"Layout",server_action:"Server Action",typed_client:"Typed client",endpoint:"Endpoint",procedure:"Procedure",e2e:"E2E",visits:"Visits",nested_serializer:"Nested serializer",nested_serializers:"Nested serializers",method_field:"SerializerMethodField",method_fields:"Method fields",from_to_representation:"to_representation",to_representation_fields:"to_representation fields",to_representation:"Custom to_representation",serializer_classes:"get_serializer_class returns",get_serializer_class_resolved:"Serializer resolved",ninja_schema:"Ninja Schema",pydantic:"Pydantic",django_form:"Django form",mutation:"Mutation",has_error_boundary:"Error boundary",invalidation:"Cache invalidation",inferred:"Inferred stitch",generated:"Generated",shared:"Shared module",element:"Renders",model_name:"Model",field_name:"Field",op:"Operation",app:"App",feature:"Feature",from_view:"From view",mentions:"Mentions",nodeid:"Test id",task:"Task",to:"Related to",doc:"Summary",template:"Template",signal:"Signal",sender:"Sender",decorators:"Decorators",nplusone:"N+1 risk",lookups:"Lookups",null:"NULL",blank:"Blank",default:"Default",max_length:"max_length",max_digits:"max_digits",decimal_places:"decimal_places",primary_key:"Primary key",help_text:"Help text",choices:"Choices",auto_now:"auto_now",auto_now_add:"auto_now_add",basename:"Router basename",args:"Args",beat:"Beat",schedule_name:"Schedule",websocket:"WebSocket",htmx:"HTMX",blocks:"Blocks",db_table:"db_table"},Sp=["doc","field_type","method","path","operation_id","raw","route","mounted_at","full_path","url_name","view","element","fields","form_fields","exclude","nested_serializer","nested_serializers","method_fields","to_representation_fields","serializer_classes","typed_client","endpoint","procedure","visits","kind","bases","permissions","authentication","throttles","pagination","filterset","on_delete","related_name","to","unique","db_index","null","blank","default","max_length","max_digits","decimal_places","primary_key","auto_now","auto_now_add","help_text","choices","relation","nplusone","lookups","template","signal","sender","decorators","basename","args","beat","schedule_name","websocket","htmx","blocks","db_table","looks_idempotent_on_pk","broker","task","model_name","field_name","op","app","feature","from_view","include","fbv","ninja","django_form","mutation","has_error_boundary","invalidation","inferred","generated","shared","queryset_in_serializer","get_queryset","get_serializer_class","dynamic","mentions","nodeid"],kp=new Set(["referenced","placeholder","booted","line","call","from","import","local","source","file","plain_handler","string_ref","pagination_sink","match","via","generated_client","django","react","superseded_by_generated","foreign_app","imported"]),mN=new Set(["looks_idempotent_on_pk","null","blank"]),yN=new Set(["inferred","generated","mutation","fbv","ninja","filterset","next_app","next_pages","server_action","e2e","ninja_schema","pydantic","method_field","trpc"]);function vN(t){return _p[t]?_p[t]:t.startsWith("react.")?"A React node on the load path.":t.startsWith("django.")?"A Django node on the load path.":t.startsWith("openapi.")?"A stitch node between Django and React.":"A node on the architecture graph."}function xN(t,r,o){const s=new Map(r.map(g=>[g.id,g])),a=[];hN.has(t.type)&&a.push("sink"),pN.has(t.type)&&a.push("contract");const u=t.extra??{};u.inferred&&a.push("inferred"),u.generated&&a.push("generated"),u.mutation&&a.push("mutation"),u.fbv&&a.push("function view"),u.ninja&&a.push("ninja"),u.ninja_schema&&a.push("ninja schema"),u.next_app&&a.push("app router"),u.typed_client&&a.push(String(u.typed_client)),u.e2e&&a.push("e2e"),u.filterset===!0&&a.push("filterset");const c=o.filter(g=>g.dst===t.id),h=o.filter(g=>g.src===t.id),p=c.slice(0,Ia).map(g=>Ra(g,s,g.src)),y=h.slice(0,Ia).map(g=>Ra(g,s,g.dst)),x=t.file_path?`${t.file_path}${t.start_line?`:${t.start_line}`:""}`:void 0,v={type:t.type,typeLabel:ns(li(t.type)),layer:Kk[si(t.type)]??"other",purpose:vN(t.type),name:t.name,qualifiedName:t.qualified_name,file:x,context:t.context,roles:a,facts:_N(u).filter(g=>!(g.key==="app"&&g.value===t.context)),inputs:p,outputs:y,extraInputs:Math.max(0,c.length-Ia),extraOutputs:Math.max(0,h.length-Ia),degreeIn:c.length,degreeOut:h.length,inputKinds:Np(c.map(g=>Ra(g,s,g.src))),outputKinds:Np(h.map(g=>Ra(g,s,g.dst))),pathSummary:""};return v.pathSummary=wN(v),v}function Np(t){const r=new Map;for(const o of t){const s=o.edgeLabel||o.edgeType.replaceAll("_"," ");r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>s[1]-o[1]||o[0].localeCompare(s[0])).map(([o,s])=>({label:o,count:s}))}function wN(t){const r=t.inputKinds.map(s=>`${s.label} ×${s.count}`).join(", "),o=t.outputKinds.map(s=>`${s.label} ×${s.count}`).join(", ");return r&&o?`${r} → this → ${o}`:o?`this → ${o}`:r?`${r} → this`:""}function Ra(t,r,o){const s=r.get(o),a=o.includes(":")?o.slice(o.indexOf(":")+1):o;return{id:o,name:(s==null?void 0:s.name)||a,type:(s==null?void 0:s.type)||"",typeLabel:s?ns(li(s.type)):"",edgeType:t.type,edgeLabel:ns(t.type),inferred:t.confidence<.8}}function _N(t){const r=[...Sp.filter(a=>a in t),...Object.keys(t).filter(a=>!Sp.includes(a)&&!kp.has(a))],o=[],s=new Set;for(const a of r){if(s.has(a)||kp.has(a)||yN.has(a))continue;s.add(a);const u=SN(a,t[a]);u!=null&&o.push({key:a,label:gN[a]??ns(a),value:u})}return o}function SN(t,r){if(r==null)return null;if(typeof r=="boolean")return!r&&!mN.has(t)?null:r?"yes":"no";if(typeof r=="number")return String(r);if(typeof r=="string")return r.trim()||null;if(Array.isArray(r)){if(r.some(u=>u&&typeof u=="object"))return kN(t,r);const o=r.map(u=>typeof u=="string"||typeof u=="number"?String(u):"").filter(Boolean);if(!o.length)return null;const s=o.slice(0,fN),a=o.length-s.length;return a>0?`${s.join(", ")} +${a} more`:s.join(", ")}return null}function kN(t,r){const o=r.slice(0,4).map(a=>{if(t==="nplusone"){const c=String(a.queryset||"queryset"),h=Array.isArray(a.accessed)?a.accessed.join("."):"",p=a.line?` L${a.line}`:"";return h?`${c} → ${h}${p}`:`${c}${p}`}if(t==="lookups"){const c=Array.isArray(a.fields)?a.fields.join(", "):"",h=String(a.kind||"filter");return c?`${h} ${c}`:h}return Object.entries(a).filter(([,c])=>c!=null&&(typeof c=="string"||typeof c=="number")).slice(0,3).map(([c,h])=>`${c}=${h}`).join(" ")});if(!o.some(Boolean))return null;const s=r.length-o.length;return s>0?`${o.join("; ")} +${s} more`:o.join("; ")}const jp=12,bp=.2,NN=.8,qa=20,jN=Dr;function bN(t,r,o){const s=o??Sm(t,r),a=[...new Set([...s.values()].map(p=>p.x))].sort((p,y)=>p-y),u=[];for(const p of r){const y=s.get(p.src),x=s.get(p.dst);if(!y||!x)continue;const v=y.y+Dr/2,g=x.y+Dr/2;if(Math.abs(v-g)S.y0-N.y0||S.y1-N.y1||S.id.localeCompare(N.id)),x=MN(y),v=Math.max(0,...x.values())+1,g=y[0].sourceX,_=EN(a,g);for(const S of y){const N=PN(x.get(S.id)??0,v),b=g+qa+Math.max(1,_-2*qa)*N;h.set(S.id,CN(S.sourceX,S.targetX,b))}}return h}function EN(t,r){const o=r-zn,s=t.find(a=>a>o+1);return s===void 0?ai:Math.max(ai,s-r)}function CN(t,r,o){const s=r-t-2*qa;return s<1?.5:Math.min(1,Math.max(0,(o-t-qa)/s))}function MN(t){const r=[],o=new Map;for(const s of t){let a=-1;for(let u=0;ur[u]+jN){a=u;break}a<0?(a=r.length,r.push(s.y1)):r[a]=Math.max(r[a],s.y1),o.set(s.id,a)}return o}function PN(t,r){return r<=1?.5:bp+(NN-bp)*t/(r-1)}const IN=new Set,RN=L.lazy(()=>I0(()=>import("./LayeredGraph3D-Ch8n5xd0.js"),[],import.meta.url).then(t=>({default:t.LayeredGraph3D}))),TN={cheap:"var(--edge-cheap)",expensive:"var(--edge-expensive)",critical:"var(--edge-critical)"},Ka={n:ke.Top,e:ke.Right,s:ke.Bottom,w:ke.Left};function LN(t,r){const o=r.x-t.x,s=r.y-t.y;return Math.abs(o)>=Math.abs(s)?o>=0?{source:"e",target:"w"}:{source:"w",target:"e"}:s>=0?{source:"s",target:"n"}:{source:"n",target:"s"}}function AN({data:t,selected:r}){const o=(t.roles||[]).map(s=>`role-${s}`).join(" ");return d.jsxs("div",{className:["lp-node",r?"selected":"",t.dim?"dim":"",o].filter(Boolean).join(" "),children:[["n","e","s","w"].map(s=>d.jsx(ii,{id:`tgt-${s}`,type:"target",position:Ka[s],isConnectable:!1},`tgt-${s}`)),d.jsx("div",{className:"t",children:li(t.type)}),d.jsx("div",{className:"n",title:t.name,children:Ar(t.name)}),["n","e","s","w"].map(s=>d.jsx(ii,{id:`src-${s}`,type:"source",position:Ka[s],isConnectable:!1},`src-${s}`))]})}const $N={load:AN},zN=new Set(["django","react","stitch","arch"]);function DN({id:t,sourceX:r,sourceY:o,targetX:s,targetY:a,sourcePosition:u,targetPosition:c,style:h,markerEnd:p,markerStart:y,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,data:b,interactionWidth:E}){const[I,w,j]=Ya({sourceX:r,sourceY:o,sourcePosition:u,targetX:s,targetY:a,targetPosition:c,borderRadius:8,stepPosition:(b==null?void 0:b.stepPosition)??.5});return d.jsx(ws,{id:t,path:I,labelX:w,labelY:j,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,style:h,markerEnd:p,markerStart:y,interactionWidth:E})}const ON={loadstep:DN};function FN({topologyKey:t}){const{fitView:r}=ll();return L.useEffect(()=>{let o=0;const s=requestAnimationFrame(()=>{o=requestAnimationFrame(()=>{r({padding:.2,maxZoom:1.15})})});return()=>{cancelAnimationFrame(s),cancelAnimationFrame(o)}},[r,t]),null}function HN(t,r,o=null,s={}){const a=new Map(t.map(v=>[v.id,v])),u=s.layout??"layers",c=iN(u),h=dN(t,r,u),p=bN(t,r,h),y=t.map(v=>{var S;const g=((S=s.roles)==null?void 0:S[v.id])||[],_=!!s.testOverlay&&!g.includes("tested")&&!g.includes("untested")&&!g.includes("test")&&!g.includes("seed");return{id:v.id,type:"load",position:h.get(v.id)??{x:0,y:0},data:{name:v.name,type:v.type,file:v.file_path,roles:g,dim:_},selected:o===v.id,sourcePosition:ke.Right,targetPosition:ke.Left,width:zn,height:Dr,style:{width:zn,height:Dr}}}),x=r.filter(v=>a.has(v.src)&&a.has(v.dst)).map(v=>{const g=TN[v.weight]||"var(--edge-cheap)",_=!!(o&&(v.src===o||v.dst===o)),S=h.get(v.src)??{x:0,y:0},N=h.get(v.dst)??{x:0,y:0},b=c?{source:"e",target:"w"}:LN(S,N);return{id:v.id,source:v.src,target:v.dst,sourceHandle:`src-${b.source}`,targetHandle:`tgt-${b.target}`,sourcePosition:Ka[b.source],targetPosition:Ka[b.target],type:c?"loadstep":"default",animated:v.weight==="critical",data:{stepPosition:p.get(v.id)??.5},style:{stroke:g,strokeWidth:v.weight==="critical"?2.4:1.2,strokeDasharray:v.confidence<.8?"6 4":void 0},markerEnd:{type:us.ArrowClosed,width:14,height:14,color:g},label:_?v.type.replaceAll("_"," "):void 0,labelStyle:_?{fill:"var(--ink)",fontSize:10,fontWeight:600}:void 0,labelBgStyle:_?{fill:"var(--graph-bg)",fillOpacity:.92}:void 0,labelBgPadding:_?[3,5]:void 0,labelBgBorderRadius:_?4:void 0}});return{rfNodes:y,rfEdges:x}}function BN({node:t,nodes:r,edges:o,onClose:s,onWhatIf:a,onSelect:u,onOpenFile:c,pinned:h,onPin:p,onIsolate:y}){const x=xN(t,r,o);return L.useEffect(()=>{const v=g=>{g.key==="Escape"&&s()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[s]),d.jsxs("aside",{className:"inspector","data-testid":"graph-inspector",children:[d.jsxs("div",{className:"inspector-head",children:[d.jsx("div",{className:"t",children:x.typeLabel}),d.jsx("div",{className:"inspector-roles",children:x.roles.map(v=>d.jsx("span",{className:"inspector-chip",children:v},v))}),d.jsx("button",{type:"button",className:"inspector-close","data-testid":"graph-inspector-close","aria-label":"Close inspector",onClick:s,children:"×"})]}),d.jsx("div",{className:"n",children:Ar(x.name)}),d.jsx("p",{className:"inspector-purpose","data-testid":"graph-inspector-purpose",children:x.purpose}),x.context?d.jsx("div",{className:"muted",children:Ar(x.context)}):null,x.file?d.jsxs("div",{className:"file-row",children:[d.jsx("div",{className:"file",children:Ar(x.file)}),c&&t.file_path?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-open-editor",onClick:()=>c(t.file_path,t.start_line),children:"Open in editor"}):null]}):null,d.jsx("div",{className:"muted",children:Ar(x.qualifiedName)}),d.jsxs("div",{className:"muted inspector-layer",children:["layer · ",x.layer]}),d.jsxs("div",{className:"muted inspector-degree","data-testid":"graph-inspector-degree",children:[x.degreeIn," in · ",x.degreeOut," out"]}),x.pathSummary?d.jsx("p",{className:"inspector-path","data-testid":"graph-inspector-path",children:x.pathSummary}):null,x.facts.length?d.jsx("dl",{className:"inspector-facts","data-testid":"graph-inspector-facts",children:x.facts.map(v=>d.jsxs("div",{className:"inspector-fact",children:[d.jsx("dt",{children:v.label}),d.jsx("dd",{children:Ar(v.value)})]},v.key))}):null,d.jsx(Ep,{title:"Inputs",testId:"graph-inspector-inputs",links:x.inputs,extra:x.extraInputs,empty:"Nothing in this graph points here.",onSelect:u}),d.jsx(Ep,{title:"Outputs",testId:"graph-inspector-outputs",links:x.outputs,extra:x.extraOutputs,empty:"This node does not point at anything in this graph.",onSelect:u}),a?d.jsx("p",{className:"whatif-hint","data-testid":"whatif-hint",children:y?"Walks a new path from this node with no git range. Isolate (next) only hides the rest of this map.":"Walks a new path from this node with no git range — as if this changed, regardless of Base/Head."}):null,d.jsxs("div",{className:"btn-row",children:[a?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-whatif",title:"Start a hypothetical walk from this node. Does not use Base/Head.",onClick:()=>a(t.id),children:"What if this changes"}):null,y?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-isolate",title:"Hide nodes that are not on a path from here to a sink. Does not start a new walk.",onClick:()=>y(t.id),children:"Isolate path to sinks"}):null,p?d.jsx("button",{type:"button",className:h?"btn primary":"btn","data-testid":"btn-pin-node",onClick:()=>p(h?null:t.id),children:h?"Unpin":"Pin"}):null]})]})}function Ep({title:t,testId:r,links:o,extra:s,empty:a,onSelect:u}){return d.jsxs("section",{className:"inspector-section","data-testid":r,children:[d.jsxs("h3",{children:[t,d.jsx("span",{className:"count",children:o.length+s})]}),o.length?d.jsx("ul",{children:o.map((c,h)=>d.jsx("li",{children:u?d.jsxs("button",{type:"button",className:"inspector-link",onClick:()=>u(c.id),children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]}):d.jsxs(d.Fragment,{children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]})},`${c.edgeType}:${c.id}:${h}`))}):d.jsx("p",{className:"muted",children:a}),s?d.jsxs("p",{className:"muted",children:["+",s," more"]}):null]})}function nc({nodes:t,edges:r,onWhatIf:o,focusPath:s,selectedId:a,onSelect:u,nodeRoles:c,testOverlay:h=!1,isolateSource:p,onIsolate:y,repoPath:x,onOpenFile:v,pinnedId:g,onPin:_}){const[S,N]=L.useState(null),b=a!==void 0?a:S,E=ue=>{a===void 0&&N(ue),u==null||u(ue)},[I,w]=L.useState(null),[j,A]=L.useState(null),[$,F]=L.useState(()=>rN()),[Y,q]=L.useState(new Set(zN)),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState(!1),W=typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,U=I??Qk(t.length),M=j??Zk(t.length),D=re?b:null,H=L.useMemo(()=>p?nN(t,r,p):null,[t,r,p]),R=H?t.filter(ue=>H.nodeIds.has(ue.id)):t,z=H?r.filter(ue=>H.edgeIds.has(ue.id)):r,ne=L.useMemo(()=>eN(R,z,{detail:M,families:Y,focusId:D,neighborhoodOnly:!!D}),[R,z,M,Y,D]),oe=L.useMemo(()=>`${$}|${ne.nodes.map(ue=>ue.id).join("\0")}|${ne.edges.map(ue=>ue.id).join("\0")}`,[$,ne.nodes,ne.edges]),fe=b?t.find(ue=>ue.id===b)??null:null,{rfNodes:he,rfEdges:pe}=L.useMemo(()=>{const ue=HN(ne.nodes,ne.edges,b,{roles:c,testOverlay:h,layout:$});return W&&(ue.rfEdges=ue.rfEdges.map(je=>({...je,animated:!1}))),ue},[ne.nodes,ne.edges,b,W,c,h,$]);L.useEffect(()=>{if(!s)return;const ue=t.find(je=>je.file_path===s);ue&&E(ue.id)},[s,t]);const Z=L.useMemo(()=>tN(t,te),[t,te]),se=(ue,je)=>{E(je.id)},me=()=>{E(null),J(!1)},Ne=fe?d.jsx(BN,{node:fe,nodes:t,edges:r,onClose:me,onWhatIf:o,onSelect:E,onOpenFile:v,pinned:g===fe.id,onPin:_,onIsolate:y?ue=>{y(p===ue?null:ue)}:void 0}):null,we=ue=>{q(je=>{const Le=new Set(je);if(Le.has(ue)){if(Le.size===1)return je;Le.delete(ue)}else Le.add(ue);return Le})},ve=L.useMemo(()=>{const ue=new Set;for(const je of t)ue.add(bm(je.type));return ue},[t]),Pe=t.length-ne.nodes.length;return d.jsxs("div",{className:"impact-graph",style:{flex:1,minHeight:0,position:"relative",display:"flex",flexDirection:"column"},children:[d.jsxs("div",{className:"graph-toolbar","data-testid":"graph-toolbar",children:[d.jsxs("div",{className:"seg","aria-label":"Graph projection",children:[d.jsx("button",{type:"button","data-testid":"graph-view-2d",className:U==="2d"?"active":"","aria-pressed":U==="2d",onClick:()=>w("2d"),children:"2D map"}),d.jsx("button",{type:"button","data-testid":"graph-view-3d",className:U==="3d"?"active":"","aria-pressed":U==="3d",onClick:()=>w("3d"),children:"3D layers"})]}),d.jsxs("div",{className:"seg","aria-label":"Graph detail",children:[d.jsx("button",{type:"button","data-testid":"graph-detail-overview",className:M==="overview"?"active":"","aria-pressed":M==="overview",onClick:()=>A("overview"),children:"Overview"}),d.jsx("button",{type:"button","data-testid":"graph-detail-full",className:M==="full"?"active":"","aria-pressed":M==="full",onClick:()=>A("full"),children:"Full"})]}),d.jsx("div",{className:"seg","aria-label":"Graph families",children:["django","stitch","react"].filter(ue=>ve.has(ue)).map(ue=>d.jsx("button",{type:"button","data-testid":`graph-family-${ue}`,className:Y.has(ue)?"active":"","aria-pressed":Y.has(ue),onClick:()=>we(ue),children:ue},ue))}),U==="2d"?d.jsxs("label",{className:"graph-layout",children:["Layout",d.jsx("select",{id:"graph-layout","data-testid":"graph-layout",value:$,"aria-label":"2D layout algorithm",onChange:ue=>{var Le;const je=(Le=xc.find(nt=>nt.id===ue.target.value))==null?void 0:Le.id;je&&(F(je),oN(je))},children:xc.map(ue=>d.jsx("option",{value:ue.id,children:ue.label},ue.id))})]}):null,d.jsx("button",{type:"button",className:re?"chip-btn active":"chip-btn","data-testid":"graph-neighborhood",disabled:!b,onClick:()=>J(ue=>!ue),children:re?"Neighborhood":"Focus neighbors"}),p?d.jsx("button",{type:"button",className:"chip-btn active","data-testid":"graph-isolate-clear",onClick:()=>y==null?void 0:y(null),children:"Path isolate"}):null,d.jsxs("label",{className:"graph-search",children:[d.jsx("span",{className:"sr-only",children:"Search nodes"}),d.jsx("input",{"data-testid":"graph-search",placeholder:"Find a node",value:te,onChange:ue=>{Q(ue.target.value),V(!0)},onFocus:()=>V(!0),onBlur:()=>window.setTimeout(()=>V(!1),150)}),C&&te.trim()&&Z.length?d.jsx("ul",{className:"graph-search-hits","data-testid":"graph-search-hits",children:Z.map(ue=>d.jsx("li",{children:d.jsxs("button",{type:"button",onMouseDown:je=>je.preventDefault(),onClick:()=>{E(ue.id),Q(""),V(!1)},children:[ue.name,d.jsx("span",{className:"muted",children:li(ue.type)})]})},ue.id))}):null]}),d.jsxs("span",{className:"muted graph-count",children:[ne.nodes.length," nodes · ",ne.edges.length," edges",Pe?` · ${Pe} hidden`:""]})]}),d.jsx("div",{className:"graph-stage",children:U==="3d"?d.jsxs("div",{className:"graph-3d","data-testid":"graph-3d",children:[d.jsx("p",{className:"graph-3d-hint",children:"Architecture layers are stacked in depth (Django → stitch → React). Drag to orbit, scroll to zoom, click a node to inspect it."}),d.jsx(L.Suspense,{fallback:d.jsx("p",{className:"muted graph-3d-hint",children:"Loading 3D layers…"}),children:d.jsx(RN,{nodes:ne.nodes,edges:ne.edges,selectedId:b,neighborIds:D?ne.neighborIds:IN,onSelect:ue=>{E(ue),ue||J(!1)}})}),Ne]}):d.jsxs(vm,{children:[d.jsxs(dk,{nodes:he,edges:pe,nodeTypes:$N,edgeTypes:ON,fitView:!1,minZoom:.25,nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,deleteKeyCode:null,onNodeClick:se,onPaneClick:me,proOptions:{hideAttribution:!1},"data-testid":"impact-graph",children:[d.jsx(FN,{topologyKey:oe}),d.jsx(mk,{}),d.jsx(zk,{pannable:!0,zoomable:!0,ariaLabel:"Impact graph overview",nodeColor:"var(--muted)",nodeStrokeColor:"transparent",nodeStrokeWidth:0,maskColor:"rgba(0, 0, 0, 0.45)",maskStrokeColor:"var(--accent)",maskStrokeWidth:1.4,bgColor:"var(--graph-bg)",style:{width:184,height:128}}),d.jsx(kk,{})]}),Ne]})})]})}function Em(){const t=localStorage.getItem("loadpath.editor")||"auto";return t==="cursor"||t==="vscode"||t==="system"?t:"auto"}function VN(t){localStorage.setItem("loadpath.editor",t)}async function WN(t,r,o,s=Em()){try{const a=await Te.openEditor(t,r,o??void 0,s);if(a.ok)return{ok:!0,message:`Opened ${r} in ${a.opened_with||"editor"}`};const u=a.urls||{},c=s==="vscode"?u.vscode:s==="cursor"?u.cursor:u.cursor||u.vscode;return c?(window.open(c,"_blank","noopener,noreferrer"),{ok:!0,message:`Opening ${r} via editor URL`}):{ok:!1,message:a.error||"Could not open editor"}}catch(a){return{ok:!1,message:a instanceof Error?a.message:String(a)}}}const Cp=[{value:"HEAD",label:"HEAD",group:"preset"},{value:"HEAD~1",label:"HEAD~1",group:"preset"}],UN=["preset","branch","tag","commit"];function GN(t){var a;if(!(t!=null&&t.git))return[...Cp];const r=((a=t.presets)!=null&&a.length?t.presets:Cp.map(u=>u.value)).map(u=>({value:u,label:u,group:"preset"})),o=new Set(r.map(u=>u.value)),s=[...r];for(const u of t.branches||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.current?`${u.name} (current)`:u.name,detail:u.subject,group:"branch"}));for(const u of t.tags||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.name,detail:u.subject,group:"tag"}));for(const u of t.commits||[])o.has(u.sha)||(o.add(u.sha),s.push({value:u.sha,label:u.short,detail:u.subject,group:"commit"}));return s}function YN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>s.value.toLowerCase().includes(o)||s.label.toLowerCase().includes(o)||(s.detail||"").toLowerCase().includes(o)):t}function XN(t){return UN.map(r=>({group:r,items:t.filter(o=>o.group===r)})).filter(r=>r.items.length>0)}function qN(t){return t==="preset"?"Common":t==="branch"?"Branches":t==="tag"?"Tags":"Recent commits"}function Mp({value:t,onChange:r,placeholder:o,testId:s,menuTestId:a,refs:u,onNeedRefs:c}){const h=L.useId(),p=L.useRef(null),[y,x]=L.useState(!1),[v,g]=L.useState(null),[_,S]=L.useState(0),N=L.useMemo(()=>{const j=GN(u);return v===null?j:YN(j,v)},[u,v]),b=L.useMemo(()=>XN(N),[N]);L.useEffect(()=>{y&&c()},[y,c]),L.useEffect(()=>{S(0)},[v,y]);const E=()=>{x(!1),g(null)},I=j=>{r(j.value),E()},w=j=>{if(j.key==="ArrowDown"){if(j.preventDefault(),!y){x(!0);return}S(A=>Math.min(A+1,Math.max(N.length-1,0)))}else if(j.key==="ArrowUp"){if(j.preventDefault(),!y)return;S(A=>Math.max(A-1,0))}else if(j.key==="Enter"&&y){j.preventDefault();const A=N[_];A&&I(A)}else j.key==="Escape"&&y&&(j.preventDefault(),E())};return d.jsxs("div",{className:"combo",ref:p,onBlur:j=>{j.currentTarget.contains(j.relatedTarget)||E()},children:[d.jsxs("div",{className:"combo-row",children:[d.jsx("input",{"data-testid":s,value:t,placeholder:o,spellCheck:!1,role:"combobox","aria-expanded":y,"aria-controls":h,"aria-autocomplete":"list",onChange:j=>{r(j.target.value),y&&g(j.target.value)},onKeyDown:w}),d.jsx("button",{type:"button",className:"icon-btn combo-toggle","data-testid":`${s}-toggle`,"aria-label":"Show recent refs","aria-expanded":y,onMouseDown:j=>j.preventDefault(),onClick:()=>y?E():x(!0),children:d.jsx(C0,{})})]}),y?d.jsx("div",{className:"combo-menu",id:h,role:"listbox","data-testid":a,children:b.length===0?d.jsx("div",{className:"combo-empty muted",children:"No matching refs — the typed value is kept"}):b.map(j=>d.jsxs("div",{className:"combo-group",children:[d.jsx("div",{className:"combo-heading",children:qN(j.group)}),j.items.map(A=>{const $=N.indexOf(A);return d.jsxs("button",{type:"button",role:"option","aria-selected":$===_,className:$===_?"combo-option active":"combo-option","data-testid":`ref-option-${A.group}`,onMouseDown:F=>F.preventDefault(),onMouseEnter:()=>S($),onClick:()=>I(A),children:[d.jsx("span",{className:"combo-label",children:A.label}),A.detail?d.jsx("span",{className:"combo-detail",children:A.detail}):null]},`${A.group}:${A.value}`)})]},j.group))}):null]})}function KN({initialPath:t,onSelect:r,onClose:o}){const[s,a]=L.useState(null),[u,c]=L.useState(t),[h,p]=L.useState(null),[y,x]=L.useState(""),[v,g]=L.useState(!1),_=L.useRef(null),S=L.useRef(0),N=async w=>{const j=S.current+1;S.current=j,g(!0);try{const A=await Te.browse(w);if(S.current!==j)return;a(A),c(A.path),p(A.is_git?A.path:null),x("")}catch(A){if(S.current!==j)return;x(A instanceof Error?A.message:String(A))}finally{S.current===j&&g(!1)}};L.useEffect(()=>{var w,j;N(t),(w=_.current)==null||w.focus(),(j=_.current)==null||j.select()},[t]);const b=h||(s==null?void 0:s.path)||u,E=h&&h!==(s==null?void 0:s.path)?h.split(/[\\/]/).filter(Boolean).pop():s!=null&&s.is_git?"this repository":"this folder",I=w=>{w.key==="Escape"&&(w.preventDefault(),o())};return d.jsx("div",{className:"modal-backdrop","data-testid":"repo-explorer","data-overlay":"true",onClick:o,onKeyDown:I,children:d.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"explorer-title",onClick:w=>w.stopPropagation(),children:[d.jsxs("div",{className:"modal-head",children:[d.jsxs("div",{children:[d.jsx("h2",{id:"explorer-title",children:"Select repository"}),d.jsx("p",{className:"muted",children:"Browse to a git root, or paste the full path."})]}),d.jsx("button",{type:"button",className:"btn ghost","data-testid":"explorer-cancel",onClick:o,children:"Cancel"})]}),d.jsxs("form",{className:"explorer-path",onSubmit:w=>{w.preventDefault(),N(u)},children:[d.jsx("input",{ref:_,"data-testid":"explorer-path",value:u,onChange:w=>c(w.target.value),spellCheck:!1,"aria-label":"Directory path"}),d.jsx("button",{type:"button",className:"btn",disabled:!(s!=null&&s.parent),onClick:()=>(s==null?void 0:s.parent)&&void N(s.parent),children:"Up"}),d.jsx("button",{type:"button",className:"btn",onClick:()=>s&&void N(s.home),children:"Home"}),d.jsx("button",{type:"submit",className:"btn",children:"Go"})]}),y?d.jsx("div",{className:"error",role:"alert",children:y}):null,d.jsx("div",{className:"explorer-list",role:"listbox","aria-label":"Folders","aria-busy":v,children:s!=null&&s.entries.length?s.entries.map(w=>{const j=h===w.path;return d.jsxs("button",{type:"button",role:"option","aria-selected":j,className:j?"explorer-row active":"explorer-row","data-testid":"explorer-entry","data-path":w.path,onClick:()=>p(w.path),onDoubleClick:()=>void N(w.path),children:[d.jsx(Tp,{}),d.jsx("span",{className:"explorer-name",children:w.name}),w.is_git?d.jsx("span",{className:"chip git-badge",children:"git"}):null]},w.path)}):d.jsx("div",{className:"muted explorer-empty",children:v?"Loading…":"No folders here"})}),d.jsxs("div",{className:"modal-foot",children:[d.jsx("span",{className:"muted explorer-current",title:b,children:b}),d.jsxs("button",{type:"button",className:"btn primary","data-testid":"explorer-use",disabled:!b,onClick:()=>b&&r(b),children:["Use ",E]})]})]})})}const QN={scan:{start:0,end:20},extract:{start:20,end:88},boot:{start:88,end:94},stitch:{start:94,end:99},skipped:{start:100,end:100},done:{start:100,end:100}},ZN=new Set(["scan","extract","boot","stitch"]);function JN(t){const r=t.phase||"";if(!r||r==="idle")return null;const o=QN[r];if(!o)return null;if(o.start===o.end)return o.end;const s=t.total||0;if(s<=0)return o.start;const a=Math.min(1,Math.max(0,(t.done||0)/s));return Math.round(o.start+(o.end-o.start)*a)}function ej(t){return!t.phase||t.phase==="idle"?null:typeof t.percent=="number"&&Number.isFinite(t.percent)?Math.max(0,Math.min(100,Math.round(t.percent))):JN(t)}const Qa=[{id:"obsidian",label:"Obsidian",group:"dark"},{id:"nord",label:"Nord",group:"dark"},{id:"solarized-dark",label:"Solarized Dark",group:"dark"},{id:"forest",label:"Forest",group:"dark"},{id:"rose",label:"Rose Pine",group:"dark"},{id:"amber",label:"Midnight Amber",group:"dark"},{id:"volcano",label:"Volcano",group:"dark"},{id:"lavender",label:"Lavender",group:"dark"},{id:"neon-noir",label:"Neon Noir",group:"dark"},{id:"synthwave",label:"Synthwave",group:"dark"},{id:"phosphor",label:"Phosphor",group:"dark"},{id:"aurora",label:"Aurora",group:"dark"},{id:"biolume",label:"Biolume",group:"dark"},{id:"carbon",label:"Carbon",group:"dark"},{id:"paper",label:"Paper",group:"light"},{id:"solarized-light",label:"Solarized Light",group:"light"},{id:"seafoam",label:"Seafoam",group:"light"},{id:"high-contrast",label:"High Contrast",group:"light"},{id:"sakura",label:"Sakura",group:"light"},{id:"citrus",label:"Citrus",group:"light"},{id:"peach",label:"Peach Fuzz",group:"light"},{id:"candy",label:"Cotton Candy",group:"light"},{id:"sky",label:"Clear Sky",group:"light"},{id:"coral",label:"Coral Reef",group:"light"}],tj="obsidian",Cm="loadpath.theme";function nj(t){return Qa.some(r=>r.id===t)}function Mm(){try{const t=localStorage.getItem(Cm)||"";if(nj(t))return t}catch{}return tj}function rj(t){var r;return((r=Qa.find(o=>o.id===t))==null?void 0:r.group)==="light"?"light":"dark"}function Pm(t){document.documentElement.dataset.theme=t,document.documentElement.style.colorScheme=rj(t);try{localStorage.setItem(Cm,t)}catch{}}const rc=[{id:"review",label:"Review",testId:"tab-review",shortcut:"1",icon:k0},{id:"architecture",label:"Architecture",testId:"tab-architecture",shortcut:"2",icon:N0},{id:"graph",label:"Impact graph",testId:"tab-graph",shortcut:"3",icon:j0},{id:"prs",label:"Pull requests",testId:"tab-prs",shortcut:"4",icon:b0},{id:"settings",label:"Settings",testId:"tab-settings",shortcut:"5",icon:E0}];function oc(t,r,o){let s;try{s=new URL(t)}catch{return}if(s.protocol!=="https:"||s.username||s.password)return;const a=s.hostname.toLowerCase();a!==r&&!a.endsWith(`.${r}`)||s.pathname.startsWith(o)&&window.open(s.toString(),"_blank","noopener,noreferrer")}function oj(){var gi,jo,mi,yi,vi,bo,Xr,an,ln,un;const[t,r]=L.useState("review"),[o,s]=L.useState(localStorage.getItem("loadpath.repo")||""),[a,u]=L.useState(localStorage.getItem("loadpath.base")||"HEAD~1"),[c,h]=L.useState(localStorage.getItem("loadpath.head")||"HEAD"),[p,y]=L.useState(null),[x,v]=L.useState(null),[g,_]=L.useState(null),[S,N]=L.useState([]),[b,E]=L.useState("review"),[I,w]=L.useState(""),[j,A]=L.useState(""),[$,F]=L.useState(null),[Y,q]=L.useState(!1),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState({}),[W,U]=L.useState([]),[M,D]=L.useState([]),[H,R]=L.useState(localStorage.getItem("loadpath.scmRepo")||""),[z,ne]=L.useState(localStorage.getItem("loadpath.provider")||"github"),[oe,fe]=L.useState(localStorage.getItem("loadpath.prNumber")||""),[he,pe]=L.useState(localStorage.getItem("loadpath.dirty")==="1"),[Z,se]=L.useState(0),[me,Ne]=L.useState(""),[we,ve]=L.useState(Mm),[Pe,ue]=L.useState(!1),[je,Le]=L.useState(!1),[nt,lt]=L.useState(!1),[ut,Ye]=L.useState(null),[wt,Yt]=L.useState(null),[gt,mt]=L.useState(localStorage.getItem("loadpath.testOverlay")==="1"),[Ct,ct]=L.useState(null),[et,On]=L.useState(localStorage.getItem("loadpath.watch")==="1"),[Mt,kn]=L.useState([]),[ui,Fn]=L.useState(null),[vo,lr]=L.useState(null),[Or,Hn]=L.useState(null),[Fr,ur]=L.useState(()=>{try{return!!(localStorage.getItem("loadpath.lastReviewId")&&(localStorage.getItem("loadpath.repo")||"").trim())}catch{return!1}}),[cr,Ft]=L.useState(null),[dt,Bn]=L.useState(null),[Vn,Nn]=L.useState(!1),[Wn,jn]=L.useState(!1),it=L.useRef(o);it.current=o;const dr=L.useRef(he);dr.current=he;const bn=L.useRef(!1);bn.current=je;const Pt=L.useRef(""),nn=L.useRef(""),xo=P=>{ve(P),Pm(P)},Ze=L.useRef(""),He=P=>{Ze.current=P,A(P)},En=P=>{let G=0,ce=!1;F(0);const Ce=()=>{Te.indexProgress(P).then(Re=>{if(!Ze.current)return;if(Re.phase&&Re.phase!=="idle"&&Re.message&&He(Re.message),ZN.has(Re.phase))ce=!0;else if(!ce)return;const mr=ej(Re);mr!=null&&(Re.phase==="scan"&&!Re.done?G=mr:G=Math.max(G,mr),F(G))}).catch(()=>{})};Ce();const Ie=window.setInterval(Ce,250);return()=>{window.clearInterval(Ie),F(null)}};L.useEffect(()=>{Te.settings().then(V).catch(()=>{}).finally(()=>ue(!0)),Te.repos().then(P=>N(P.repos)).catch(()=>{})},[]);const Un=()=>o.trim()?!0:(w("Point at a local repository path first."),!1);L.useEffect(()=>{if(t!=="architecture"||!o.trim())return;const P=o;let G=!1;return nn.current!==P&&Yn(P),Te.config(P).then(ce=>{!G&&it.current===P&&lr(ce)}).catch(()=>{}),Te.architectureHealth(P).then(ce=>{!G&&it.current===P&&Hn(ce)}).catch(()=>{}),()=>{G=!0}},[t,o]);const rn=P=>{it.current=P,s(P),localStorage.setItem("loadpath.repo",P),P.trim()!==Pt.current&&(Pt.current="",Ft(null))},Hr=L.useCallback(P=>{const G=(P??it.current).trim();return!G||Pt.current===G?Promise.resolve():(Pt.current=G,Te.gitRefs(G).then(ce=>{it.current.trim()===G&&Ft(ce)}).catch(()=>{Pt.current===G&&(Pt.current="",Ft(null))}))},[]),on=(P,G)=>{u(P),h(G),localStorage.setItem("loadpath.base",P),localStorage.setItem("loadpath.head",G)},It=(P,G,ce)=>{ne(P),R(G),localStorage.setItem("loadpath.provider",P),localStorage.setItem("loadpath.scmRepo",G),ce!==void 0&&(fe(ce),localStorage.setItem("loadpath.prNumber",ce))},Xt=P=>{y(P),se(0),Ye(wt&&P.nodes.some(G=>G.id===wt)?wt:null),ct(null),Fn(null),P.what_if||(v(P),P.id&&localStorage.setItem("loadpath.lastReviewId",P.id))},Gn=async P=>{try{const G=await Te.reviews(P);kn(G.reviews)}catch{kn([])}},wo=async P=>{try{Hn(await Te.architectureHealth(P))}catch{Hn(null)}},_o=P=>P==="github"?!!C.github_token_set:P==="gitlab"?!!C.gitlab_token_set:!!C.bitbucket_token_set,Rt=L.useCallback(async(P=z)=>{var G;try{const ce=await Te.scmRepos(P);D(ce.repos),(G=ce.user)!=null&&G.login&&V(Ce=>({...Ce,...P==="github"?{github_user:ce.user.login}:P==="gitlab"?{gitlab_user:ce.user.login}:{bitbucket_user:ce.user.login}}))}catch{D([])}},[z]);L.useEffect(()=>{if(t!=="prs")return;let P=!1;return Rt(z).catch(()=>{P||D([])}),()=>{P=!0}},[t,z,Rt]),L.useEffect(()=>{if(!dt)return;let P=!1,G=0;const ce=async()=>{try{const Ce=await Te.githubOAuthPoll(dt.flow_id);if(P)return;if(Ce.status==="complete"){Bn(null);const Ie=await Te.settings();V(Ie),Q(Ce.user?`Signed in to GitHub as ${Ce.user}`:"Signed in to GitHub"),Rt("github");return}if(Ce.status==="pending"||Ce.status==="slow_down"){G=window.setTimeout(ce,Math.max(Ce.interval||dt.interval,5)*1e3);return}Bn(null),w(Ce.status==="denied"?"GitHub sign-in was denied.":"GitHub sign-in expired. Try again.")}catch(Ce){if(P)return;Bn(null),w(Ce instanceof Error?Ce.message:String(Ce))}};return G=window.setTimeout(ce,Math.max(dt.interval,5)*1e3),()=>{P=!0,window.clearTimeout(G)}},[dt,Rt]),L.useEffect(()=>{if(!Vn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.bitbucket.connected){Nn(!1);const Re=await Te.settings();V(Re),Q(Ie.bitbucket.user?`Signed in to Bitbucket as ${Ie.bitbucket.user}`:"Signed in to Bitbucket"),Rt("bitbucket");return}if(Date.now()-ce>18e4){Nn(!1),w("Bitbucket sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;Nn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Vn,Rt]),L.useEffect(()=>{if(!Wn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.gitlab.connected){jn(!1);const Re=await Te.settings();V(Re),Q(Ie.gitlab.user?`Signed in to GitLab as ${Ie.gitlab.user}`:"Signed in to GitLab"),Rt("gitlab");return}if(Date.now()-ce>18e4){jn(!1),w("GitLab sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;jn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Wn,Rt]);const Yn=async(P=o,G=!1)=>{if(!P.trim())return null;nn.current=P,J(!0);try{const ce=await Te.architecture(P,!1);it.current===P&&_(ce);const Ce=Te.architectureGraph(P).then(Ie=>{it.current===P&&_(Re=>Re&&{...Re,nodes:Ie.nodes,edges:Ie.edges,graph_pending:!1})});return Ce.catch(()=>{_(Ie=>Ie&&it.current===P?{...Ie,graph_pending:!1}:Ie)}).finally(()=>{nn.current===P&&J(!1)}),G&&await Ce,ce}catch(ce){throw it.current===P&&J(!1),ce}},Br=async P=>{const G=P.trim();if(!(!G||G===it.current)){if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}w(""),Q(""),y(null),v(null),_(null),E("architecture"),rn(G),q(!0),He(`Loading ${S0(G)}…`);try{await Promise.all([Yn(G),Hr(G)])}catch(ce){it.current===G&&w(ce instanceof Error?ce.message:String(ce))}finally{it.current===G&&(He(""),q(!1))}}},Xn=async()=>{if(Ze.current||!Un())return;w(""),Q(""),He("Tracing load path…"),rn(o),on(a,c);const P=En(o);try{const G=await Te.review(o,a,c,!0,dr.current);Xt(G),E("review"),r("review"),await Te.repos().then(ce=>N(ce.repos)).catch(()=>{}),await Promise.all([Yn(o),Gn(o),wo(o)])}catch(G){w(G instanceof Error?G.message:String(G))}finally{P(),He("")}},fr=async(P=!0)=>{if(Ze.current||!Un())return;w(""),Q(""),He(P?"Indexing…":"Full reindex…"),rn(o);const G=En(o);try{await Te.index(o,P);const ce=await Yn(o);await Te.repos().then(Ce=>N(Ce.repos)).catch(()=>{}),ce!=null&&ce.indexed&&(E("architecture"),r("architecture"))}catch(ce){w(ce instanceof Error?ce.message:String(ce))}finally{G(),He("")}},Ve=async()=>{if(!Ze.current&&Un()){w(""),Q(""),He("Detecting layout…"),rn(o);try{const P=await Te.init(o);Q(P.message),await Te.repos().then(G=>N(G.repos)).catch(()=>{})}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},ci=async()=>{if(p!=null&&p.markdown)try{await navigator.clipboard.writeText(p.markdown),Q("Copied markdown brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Vr=async()=>{if(!Ze.current){if(p!=null&&p.what_if){w("What-if walks are hypothetical — they are not posted to a pull request. Restore the git-range walk first.");return}if(!(p!=null&&p.markdown)||!H||!oe){w("Pick a pull request first (Pull requests tab), then post the brief.");return}He("Posting Loadpath brief…");try{const P=await Te.postComment(z,H,Number(oe),p.markdown);Q(P.updated?"Updated the Loadpath PR comment":"Posted the Loadpath PR comment")}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},So=async()=>{if(!Ze.current){w(""),He("Fetching pull requests…");try{const P=await Te.prs(z,H,"open",o.trim()||void 0);U(P.pull_requests);const G=M.find(ce=>ce.slug.toLowerCase()===H.trim().toLowerCase());G!=null&&G.local_path&&rn(G.local_path)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},hr=async()=>{w("");try{const P=await Te.githubOAuthStart();Bn(P),oc(P.verification_uri_complete,"github.com","/login/device")}catch(P){w(P instanceof Error?P.message:String(P))}},di=async()=>{w("");try{const P=await Te.bitbucketOAuthStart();Nn(!0),oc(P.authorize_url,"bitbucket.org","/site/oauth2/authorize")}catch(P){Nn(!1),w(P instanceof Error?P.message:String(P))}},ko=async()=>{w("");try{const P=await Te.gitlabOAuthStart();jn(!0),oc(P.authorize_url,new URL(P.authorize_url).hostname,"/oauth/authorize")}catch(P){jn(!1),w(P instanceof Error?P.message:String(P))}},Cn=async P=>{if(!(Ze.current||!o.trim())){w(""),He("Walking what-if path…");try{const G=await Te.whatIf(o,P);Q(`${G.title} — ${G.confidence.level} · ${(G.sinks||[]).length} sinks`),Xt({...G,markdown:G.markdown||"",index:G.index||(p==null?void 0:p.index),workspace:G.workspace||(p==null?void 0:p.workspace)}),E("review"),r("review")}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},_t=()=>{if(x){Xt(x),E("review"),r("review"),Q("Restored the last git-range walk");return}y(null),se(0),Ye(null),ct(null),Fn(null),E("architecture"),r("architecture"),Q("")},fi=async P=>{var Ie;if(Ze.current)return;It(P.provider,P.repo,String(P.number));const G=M.find(Re=>Re.slug.toLowerCase()===P.repo.toLowerCase());G!=null&&G.local_path&&rn(G.local_path),w(""),He(`Fetching ${P.provider} #${P.number}…`);const ce=(G==null?void 0:G.local_path)||o,Ce=ce?En(ce):()=>{};try{const Re=await Te.reviewPr(P.provider,P.repo,P.number,(G==null?void 0:G.local_path)||o||void 0);Xt(Re),Re.pull_request&&typeof Re.pull_request.repo_path=="string"&&rn(Re.pull_request.repo_path),on(String(Re.base||P.target_branch),String(Re.head||P.source_branch)),E("review"),r("review"),typeof((Ie=Re.pull_request)==null?void 0:Ie.repo_path)=="string"&&Gn(Re.pull_request.repo_path)}catch(Re){on(P.base_sha||P.target_branch,P.head_sha||P.source_branch),r("review"),w(Re instanceof Error?Re.message:String(Re))}finally{Ce(),He("")}},yt=async P=>{w("");try{V(await Te.oauthDisconnect(P)),z===P&&D([]),Q(`Disconnected ${P}`)}catch(G){w(G instanceof Error?G.message:String(G))}},hi=async P=>{P.preventDefault();const G=new FormData(P.currentTarget),ce={github_token:String(G.get("github_token")||""),github_oauth_client_id:String(G.get("github_oauth_client_id")||""),github_host:String(G.get("github_host")||""),gitlab_token:String(G.get("gitlab_token")||""),gitlab_host:String(G.get("gitlab_host")||""),gitlab_oauth_client_id:String(G.get("gitlab_oauth_client_id")||""),gitlab_oauth_client_secret:String(G.get("gitlab_oauth_client_secret")||""),bitbucket_token:String(G.get("bitbucket_token")||""),bitbucket_username:String(G.get("bitbucket_username")||""),bitbucket_oauth_client_id:String(G.get("bitbucket_oauth_client_id")||""),bitbucket_oauth_client_secret:String(G.get("bitbucket_oauth_client_secret")||""),ai_provider:String(G.get("ai_provider")||"none"),ai_api_key:String(G.get("ai_api_key")||""),ai_model:String(G.get("ai_model")||""),ai_base_url:String(G.get("ai_base_url")||"")},Ce=S.length?{...ce,workspaces:S.map(Ie=>({path:Ie.path,name:Ie.name}))}:ce;try{V(await Te.saveSettings(Ce)),Q("Settings saved on this machine")}catch(Ie){w(Ie instanceof Error?Ie.message:String(Ie))}},pi=async()=>{if(!(!p||Ze.current)){He("Residual analysis…");try{const P=await Te.residual(p);Ne(P.note)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},Wr=L.useRef(Xn);Wr.current=Xn;const Mn=L.useRef(t);Mn.current=t;const qn=L.useRef(!1);qn.current=nt;const Pn=L.useRef(p);Pn.current=p;const qt=L.useRef(Z);qt.current=Z,L.useEffect(()=>{const P=localStorage.getItem("loadpath.lastReviewId"),G=(localStorage.getItem("loadpath.repo")||"").trim();if(!P||!G){ur(!1);return}let ce=!1;return Te.getReview(G,P).then(Ce=>{ce||(Xt(Ce),on(Ce.base||localStorage.getItem("loadpath.base")||"HEAD~1",Ce.head||localStorage.getItem("loadpath.head")||"HEAD"),Gn(G),wo(G))}).catch(()=>{}).finally(()=>{ce||ur(!1)}),()=>{ce=!0}},[]);const Ur=L.useRef("");L.useEffect(()=>{if(!et||!o.trim())return;let P=!1;const G=async()=>{try{const Ce=await Te.workspaceStatus(o);if(P)return;Ur.current&&Ce.fingerprint!==Ur.current&&!Ze.current&&(pe(!0),dr.current=!0,localStorage.setItem("loadpath.dirty","1"),Wr.current()),Ur.current=Ce.fingerprint}catch{}};G();const ce=window.setInterval(G,2e3);return()=>{P=!0,window.clearInterval(ce)}},[et,o]),L.useEffect(()=>{const P=G=>{var Ie;if((G.metaKey||G.ctrlKey)&&G.key.toLowerCase()==="k"){G.preventDefault(),lt(Re=>!Re);return}if(qn.current){G.key==="Escape"&&(G.preventDefault(),lt(!1));return}if(bn.current){G.key==="Escape"&&(G.preventDefault(),Le(!1));return}const ce=G.target;if(ce&&(ce.tagName==="INPUT"||ce.tagName==="TEXTAREA"||ce.tagName==="SELECT"||ce.isContentEditable)){G.key==="Escape"&&ce.blur();return}if(G.key==="Escape"){w(""),Q(""),Ye(wt),ct(null);return}if(G.key==="j"||G.key==="k"){const Re=((Ie=Pn.current)==null?void 0:Ie.read_order)||[];if(!Re.length)return;G.preventDefault();const xi=qt.current,mr=G.key==="j"?Math.min(Re.length-1,xi+1):Math.max(0,xi-1);se(mr);return}const Ce=rc.find(Re=>Re.shortcut===G.key);if(Ce&&!G.metaKey&&!G.ctrlKey&&!G.altKey&&r(Ce.id),(G.metaKey||G.ctrlKey)&&G.key==="Enter"){if(Mn.current==="settings"||Mn.current==="prs"||Ze.current)return;G.preventDefault(),Wr.current()}};return window.addEventListener("keydown",P),()=>window.removeEventListener("keydown",P)},[wt]);const Gr=async(P,G)=>{if(!o.trim())return;const ce=await WN(o,P,G);ce.ok?Q(ce.message):w(ce.message)},pr=async()=>{if(p)try{const P=await Te.exportHtml(p),G=URL.createObjectURL(P),ce=document.createElement("a");ce.href=G,ce.download=`loadpath-${(p.id||"review").slice(0,8)}.html`,ce.click(),URL.revokeObjectURL(G),Q("Saved HTML brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Yr=async P=>{if(o.trim()){He("Loading stored review…");try{const G=await Te.getReview(o,P);Xt(G),on(G.base||a,G.head||c),E("review"),r("review");const ce=Mt.findIndex(Ie=>Ie.id===P),Ce=ce>=0?Mt[ce+1]:void 0;if(Ce)try{Fn(await Te.reviewDiff(o,P,Ce.id))}catch{Fn(null)}}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},sn={selectedId:ut,onSelect:Ye,nodeRoles:p==null?void 0:p.node_roles,testOverlay:gt,isolateSource:Ct,onIsolate:ct,repoPath:o,onOpenFile:Gr,pinnedId:wt,onPin:Yt},Kn=[{id:"review",group:"Run",label:"Review this range",hint:"⌘/Ctrl+Enter",run:()=>void Xn()},...p!=null&&p.what_if?[{id:"exit-whatif",group:"Review",label:x?"Back to git-range walk":"Exit what-if walk",run:_t}]:[],{id:"index",group:"Run",label:"Index repository",run:()=>void fr(!0)},{id:"watch",group:"Run",label:et?"Stop watching working tree":"Watch working tree",run:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")}},{id:"tests",group:"Graph",label:gt?"Hide test overlay":"Show test overlay",run:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")}},{id:"export",group:"Review",label:"Export HTML brief",run:()=>void pr()},...rc.map(P=>({id:`tab-${P.id}`,group:"Tabs",label:`Go to ${P.label}`,hint:P.shortcut,run:()=>r(P.id)})),...((p==null?void 0:p.nodes)||[]).slice(0,30).map(P=>({id:`node-${P.id}`,group:"Nodes",label:P.name,hint:li(P.type),run:()=>{Ye(P.id),r("graph")}})),...Mt.slice(0,12).map(P=>({id:`hist-${P.id}`,group:"History",label:P.title||P.id,hint:`${P.level||""} ${P.created_at||""}`.trim(),run:()=>void Yr(P.id)}))],No=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.nodes)??[]:(p==null?void 0:p.nodes)??[],[b,g,p]),gr=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.edges)??[]:(p==null?void 0:p.edges)??[],[b,g,p]),Fe=p!=null&&p.index?`${p.index.counts.nodes} nodes · ${p.index.counts.edges} edges`:g!=null&&g.indexed?`${g.counts.nodes} nodes · ${g.counts.edges} edges`:"Not indexed",_s=((p==null?void 0:p.findings)||[]).filter(P=>!P.waived);return d.jsxs("div",{className:"app",children:[d.jsx("a",{className:"skip",href:"#main",children:"Skip to content"}),d.jsxs("nav",{className:"rail","data-testid":"rail","aria-label":"Primary",children:[d.jsxs("div",{className:"brand",children:[d.jsx("div",{className:"brand-mark",children:"Loadpath"}),d.jsx("div",{className:"brand-sub",children:"Load-path review"})]}),rc.map(P=>{const G=P.icon,ce=t===P.id;return d.jsxs("button",{type:"button","data-testid":P.testId,className:ce?"nav-item active":"nav-item","aria-current":ce?"page":void 0,"aria-label":P.label,onClick:()=>r(P.id),children:[d.jsx(G,{}),d.jsx("span",{children:P.label})]},P.id)}),d.jsxs("div",{className:"theme-pick",children:[d.jsx("label",{htmlFor:"theme-select",children:"Theme"}),d.jsx("select",{id:"theme-select","data-testid":"theme-select",value:we,onChange:P=>xo(P.target.value),children:["dark","light"].map(P=>d.jsx("optgroup",{label:P==="dark"?"Dark":"Light",children:Qa.filter(G=>G.group===P).map(G=>d.jsx("option",{value:G.id,children:G.label},G.id))},P))})]}),d.jsxs("div",{className:"rail-foot",children:[d.jsx("div",{className:"muted",role:"status",children:j||Fe}),d.jsxs("div",{className:"kbd-hint",children:[d.jsx("kbd",{children:"1"}),"–",d.jsx("kbd",{children:"5"})," tabs · ",d.jsx("kbd",{children:"⌘"}),d.jsx("kbd",{children:"K"})," palette · ",d.jsx("kbd",{children:"j"}),"/",d.jsx("kbd",{children:"k"})," read order"]})]})]}),d.jsxs("div",{className:"main",id:"main",children:[j?d.jsxs("div",{className:$!=null?"progress determinate":"progress",role:$!=null?"progressbar":"status","aria-label":j,"aria-live":"polite","aria-busy":"true","aria-valuemin":$!=null?0:void 0,"aria-valuemax":$!=null?100:void 0,"aria-valuenow":$??void 0,"data-testid":"progress",children:[d.jsx("i",{style:$!=null?{width:`${$}%`}:void 0}),d.jsx("span",{className:"sr-only",children:j})]}):null,d.jsxs("header",{className:"topbar","data-testid":"topbar",children:[S.length>0?d.jsxs("label",{className:"field workspace",children:[d.jsx("span",{children:"Workspace"}),d.jsxs("select",{"data-testid":"workspace-select",value:S.some(P=>P.path===o)?o:"",disabled:!!j,"aria-busy":Y,onChange:P=>{P.target.value&&Br(P.target.value)},children:[d.jsx("option",{value:"",children:"Indexed repos…"}),S.map(P=>d.jsxs("option",{value:P.path,children:[P.name,P.indexed?` (${P.counts.nodes})`:""]},P.path))]})]}):null,d.jsxs("label",{className:"field path",children:[d.jsx("span",{children:"Repository"}),d.jsxs("div",{className:"path-row",children:[d.jsx("input",{"data-testid":"repo-path",placeholder:"Local monorepo path",value:o,onChange:P=>{const G=P.target.value;s(G),G.trim()!==Pt.current&&(Pt.current="",Ft(null))},spellCheck:!1}),d.jsx("button",{type:"button",className:"icon-btn","data-testid":"btn-browse-repo","aria-label":"Browse for a local repository",onClick:()=>Le(!0),children:d.jsx(Tp,{})})]})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Base"}),d.jsx(Mp,{testId:"base-ref",menuTestId:"base-ref-menu",value:a,onChange:P=>on(P,c),placeholder:"base",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Head"}),d.jsx(Mp,{testId:"head-ref",menuTestId:"head-ref-menu",value:c,onChange:P=>on(a,P),placeholder:"head",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Working tree"}),d.jsx("button",{type:"button",className:he?"chip-btn active":"chip-btn","data-testid":"btn-dirty","aria-pressed":he,onClick:()=>{const P=!he;pe(P),localStorage.setItem("loadpath.dirty",P?"1":"0")},children:he?"Include uncommitted":"Committed range"})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Watch"}),d.jsx("button",{type:"button",className:et?"chip-btn active":"chip-btn","data-testid":"btn-watch","aria-pressed":et,onClick:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")},children:et?"Watching":"Paused"})]}),p?d.jsxs("div",{className:`merge-box compact ${p.confidence.level}`,"data-testid":"merge-box",children:[d.jsx("div",{className:`level ${p.confidence.level}`,children:p.confidence.level.toUpperCase()}),d.jsxs("div",{className:"muted",children:[p.what_if?"what-if · ":"",p.confidence.covered_sinks,"/",p.confidence.sinks," sinks"]})]}):null,d.jsxs("div",{className:"topbar-actions",children:[d.jsx("button",{type:"button","data-testid":"btn-init",disabled:!!j,onClick:Ve,children:"Draft config"}),d.jsx("button",{type:"button","data-testid":"btn-index",disabled:!!j,onClick:()=>fr(!0),children:"Index"}),d.jsx("button",{type:"button","data-testid":"btn-review",className:"btn primary",disabled:!!j,onClick:Xn,children:"Review"})]})]}),d.jsxs("div",{className:"alerts",children:[I?d.jsxs("div",{className:"error","data-testid":"error",role:"alert",children:[d.jsx("span",{children:I}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>w(""),"aria-label":"Dismiss error",children:"×"})]}):null,te?d.jsxs("div",{className:"banner","data-testid":"status-note",children:[d.jsx("span",{children:te}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>Q(""),"aria-label":"Dismiss",children:"×"})]}):null,((gi=p==null?void 0:p.index)!=null&&gi.stale||g!=null&&g.stale)&&(t==="review"||t==="architecture")?d.jsx("div",{className:"banner stale","data-testid":"index-stale",children:"Index is stale — files changed since the last extract. Index again before trusting this walk."}):null,((jo=p==null?void 0:p.index)==null?void 0:jo.django_boot)==="failed"||(g==null?void 0:g.django_boot)==="failed"?d.jsx("div",{className:"banner warn","data-testid":"django-boot-failed",children:((mi=p==null?void 0:p.index)==null?void 0:mi.django_boot_detail)||(g==null?void 0:g.django_boot_detail)||"django.setup() failed"}):null,(yi=p==null?void 0:p.workspace)!=null&&yi.dirty_overlaps_review&&t==="review"?d.jsxs("div",{className:"banner warn","data-testid":"dirty-tree",children:["Uncommitted files overlap this review: ",(p.workspace.dirty_overlap||[]).slice(0,6).join(", ")]}):null,p!=null&&p.what_if?d.jsxs("div",{className:"banner whatif","data-testid":"whatif-banner",children:[d.jsxs("span",{children:["Hypothetical walk from"," ",d.jsx("strong",{children:((vi=p.node)==null?void 0:vi.name)||"this node"}),". Loadpath ignored Base/Head and asked which sinks would feel this node change — not a filter of the current map."]}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-exit-whatif",onClick:_t,children:x?"Back to git range":"Back to architecture"})]}):null,Y?d.jsx("div",{className:"banner","data-testid":"workspace-loading",children:j||"Loading workspace…"}):null]}),d.jsxs("div",{className:"stage","aria-busy":Y||re,children:[t==="review"&&d.jsxs("div",{className:"content","data-testid":"review-layout",children:[d.jsx("aside",{className:"brief","data-testid":"brief",children:p?d.jsx(ij,{review:p,findings:_s,aiNote:me,busy:!!j,tourIndex:Z,onTour:se,onAskAi:pi,onCopy:ci,onPost:Vr,onSelect:Ye,onOpenFile:Gr,onExport:pr,history:Mt,diff:ui,onReopen:Yr,onWaiver:(P,G)=>{o.trim()&&Te.addWaiver(o,P,G||void 0,"from review").then(ce=>{lr(ce),Q(`Waived ${P} in loadpath.yml`)})}}):Fr?d.jsxs("div",{className:"empty","data-testid":"review-restoring",children:[d.jsx("h2",{children:"Restoring last review"}),d.jsx("p",{children:"Loading the walk this machine stored last time Loadpath was open."})]}):d.jsxs("div",{className:"empty","data-testid":"review-empty",children:[d.jsx("h2",{children:"Trace the force of this diff"}),d.jsx("p",{children:"The graph is the architecture. The brief is where this change travels — not a hunk list."}),d.jsxs("ol",{children:[d.jsx("li",{children:"Point at a Django + React monorepo, or pick an indexed workspace."}),d.jsxs("li",{children:["Index it. Missing ",d.jsx("code",{children:"loadpath.yml"})," is drafted from ",d.jsx("code",{children:"manage.py"})," and"," ",d.jsx("code",{children:"src/features"}),"."]}),d.jsx("li",{children:"Review a git range, or open a pull request so base/head become a three-dot merge-base."})]})]})}),d.jsx("div",{className:"graph-wrap","data-testid":"review-graph",children:p?d.jsx(nc,{nodes:p.nodes,edges:p.edges,onWhatIf:Cn,focusPath:(bo=p.read_order[Z])==null?void 0:bo.path,...sn}):null})]}),t==="architecture"&&d.jsxs("div",{className:"content","data-testid":"architecture-panel",children:[d.jsx("aside",{className:"brief","data-testid":"architecture-brief",children:g!=null&&g.indexed?d.jsx(sj,{architecture:g,busy:!!j,onReindex:()=>fr(!1),onReview:Xn,onSelect:Ye,config:vo,health:Or,onSaveConfig:P=>{Te.saveConfig(o,P).then(G=>{lr(G),Q("Wrote loadpath.yml")})},onWaiver:(P,G,ce)=>{Te.addWaiver(o,P,G,ce).then(Ce=>{lr(Ce),Q(`Waived ${P}`)})}}):Y?d.jsx("p",{className:"muted","data-testid":"architecture-loading",children:"Loading the index summary…"}):d.jsx("p",{className:"muted","data-testid":"architecture-empty",children:"Index this repo to build the architecture graph. Review then walks that same graph for a git range — it does not start from a hunk list."})}),d.jsx("div",{className:"graph-wrap","data-testid":"architecture-graph",children:(re||g!=null&&g.graph_pending)&&!((g==null?void 0:g.nodes)||[]).length?d.jsxs("div",{className:"empty graph-loading","data-testid":"graph-loading",children:[d.jsx("h2",{children:"Drawing the architecture map…"}),d.jsx("p",{children:(Xr=g==null?void 0:g.counts)!=null&&Xr.nodes?`${g.counts.nodes} indexed nodes. The brief is ready while the graph loads.`:"Fetching the indexed graph."})]}):g!=null&&g.indexed?d.jsx(nc,{nodes:g.nodes,edges:g.edges,onWhatIf:Cn,...sn,isolateSource:null,onIsolate:void 0}):null})]}),t==="graph"&&d.jsxs("div",{className:"graph-wrap","data-testid":"graph-full",style:{height:"100%"},children:[d.jsxs("div",{className:"graph-modes",children:[d.jsxs("div",{className:"seg","aria-label":"Graph scope",children:[d.jsx("button",{type:"button","aria-pressed":b==="review","data-testid":"graph-mode-review",className:b==="review"?"active":"",onClick:()=>E("review"),children:"This review"}),d.jsx("button",{type:"button","aria-pressed":b==="architecture","data-testid":"graph-mode-architecture",className:b==="architecture"?"active":"",onClick:()=>E("architecture"),children:"Indexed architecture"})]}),d.jsxs("div",{className:"legend","aria-hidden":"true",children:[d.jsxs("span",{children:[d.jsx("i",{})," cheap"]}),d.jsxs("span",{children:[d.jsx("i",{className:"exp"})," expensive"]}),d.jsxs("span",{children:[d.jsx("i",{className:"crit"})," critical"]}),d.jsxs("span",{children:[d.jsx("i",{className:"dash"})," inferred"]}),d.jsxs("span",{children:[d.jsx("i",{className:"seed"})," changed"]}),d.jsxs("span",{children:[d.jsx("i",{className:"down"})," downstream"]})]}),d.jsx("button",{type:"button",className:gt?"chip-btn active":"chip-btn","data-testid":"graph-test-overlay","aria-pressed":gt,onClick:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")},children:"Tests"})]}),No.length?d.jsx(nc,{nodes:No,edges:gr,onWhatIf:Cn,...sn,...b==="architecture"?{isolateSource:null,onIsolate:void 0,nodeRoles:void 0,testOverlay:!1}:{}}):re||g!=null&&g.graph_pending?d.jsx("p",{className:"empty","data-testid":"graph-loading",children:"Drawing the architecture map…"}):d.jsx("p",{className:"empty","data-testid":"graph-empty",children:"Index the repo or run a review first. Click a node to inspect it."})]}),t==="prs"&&d.jsxs("div",{className:"pr-list","data-testid":"pr-list",children:[d.jsxs("div",{className:"pr-toolbar",children:[d.jsxs("label",{className:"field provider",children:[d.jsx("span",{children:"Provider"}),d.jsxs("select",{"data-testid":"pr-provider",value:z,onChange:P=>It(P.target.value,H,oe),children:[d.jsx("option",{value:"github",children:"GitHub"}),d.jsx("option",{value:"gitlab",children:"GitLab"}),d.jsx("option",{value:"bitbucket",children:"Bitbucket"})]})]}),d.jsxs("label",{className:"field",children:[d.jsx("span",{children:"Repository"}),d.jsx("input",{"data-testid":"pr-repo",placeholder:M.length?"Search your repos":"owner/repo",value:H,onChange:P=>It(z,P.target.value,oe),list:"scm-repos",spellCheck:!1}),d.jsx("datalist",{id:"scm-repos",children:M.map(P=>d.jsxs("option",{value:P.slug,children:[P.private?"private":"public",P.local_path?" · local":""]},P.slug))})]}),d.jsx("button",{type:"button","data-testid":"btn-refresh-repos",className:"btn",disabled:!!j||!_o(z),onClick:()=>{Rt(z)},children:"My repos"}),d.jsx("button",{type:"button","data-testid":"btn-list-prs",className:"btn",disabled:!!j,onClick:So,children:"List PRs"})]}),M.length>0?d.jsxs("p",{className:"muted scm-count","data-testid":"scm-repo-count",children:[M.length," ",z," repositor",M.length===1?"y":"ies",z==="github"&&C.github_user?` · @${String(C.github_user)}`:"",z==="gitlab"&&C.gitlab_user?` · @${String(C.gitlab_user)}`:"",z==="bitbucket"&&C.bitbucket_user?` · ${String(C.bitbucket_user)}`:""]}):null,W.length===0?d.jsxs("div",{className:"empty","data-testid":"pr-empty",children:[d.jsx("h2",{children:"No pull requests loaded"}),d.jsx("p",{children:"Sign in under Settings (or paste a token), load your repositories, then list open PRs. Reviewing a PR fills base and head from its SHAs."})]}):W.map(P=>{var G;return d.jsxs("article",{className:"pr","data-testid":`pr-${P.number}`,children:[d.jsxs("h3",{children:["#",P.number," ",P.title]}),d.jsxs("div",{className:"pr-meta muted",children:[d.jsx("span",{className:`chip ${P.draft?"":"open"}`,children:P.draft?"draft":P.state}),d.jsx("span",{children:P.author}),d.jsxs("span",{children:[P.source_branch," → ",P.target_branch]}),P.loadpath?d.jsxs("span",{className:`chip ${P.loadpath.level||""}`,"data-testid":`pr-loadpath-${P.number}`,children:[((G=P.loadpath.level)==null?void 0:G.toUpperCase())||"REVIEWED",P.loadpath.contract_break&&P.loadpath.contract_break!=="none"?` · ${P.loadpath.contract_break}`:""]}):d.jsx("span",{className:"muted",children:"no Loadpath walk yet"})]}),d.jsxs("div",{className:"pr-actions",children:[d.jsxs("a",{href:P.url,target:"_blank",rel:"noreferrer",children:["Open on ",P.provider]}),d.jsx("button",{type:"button",className:"btn primary","data-testid":`pr-review-${P.number}`,onClick:()=>void fi(P),children:"Review this PR"})]})]},`${P.provider}-${P.number}`)})]}),t==="settings"&&Pe&&d.jsxs("form",{className:"settings","data-testid":"settings-form",onSubmit:hi,children:[d.jsxs("div",{children:[d.jsx("h1",{children:"Settings"}),d.jsx("p",{className:"muted",children:"Tokens stay on this machine in ~/.loadpath/settings.json. AI runs only on residual uncertainty the graph could not close."})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Appearance"}),d.jsx("p",{className:"muted",children:"Local to this browser. High contrast is a first-class theme, not an afterthought."}),d.jsx("div",{className:"theme-grid","data-testid":"theme-grid",children:Qa.map(P=>d.jsxs("button",{type:"button","data-theme":P.id,className:we===P.id?"theme-swatch active":"theme-swatch","data-testid":`theme-${P.id}`,onClick:()=>xo(P.id),children:[d.jsx("div",{className:"swatch-bar","aria-hidden":"true"}),d.jsx("div",{className:"name",children:P.label}),d.jsx("div",{className:"group",children:P.group})]},P.id))})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Editor"}),d.jsx("p",{className:"muted",children:"Open files from the inspector and read-order in Cursor, VS Code, or the system handler."}),d.jsx("label",{htmlFor:"editor-pref",children:"Preferred editor"}),d.jsxs("select",{id:"editor-pref","data-testid":"editor-pref",defaultValue:Em(),onChange:P=>VN(P.target.value),children:[d.jsx("option",{value:"auto",children:"Auto (Cursor, then VS Code)"}),d.jsx("option",{value:"cursor",children:"Cursor"}),d.jsx("option",{value:"vscode",children:"VS Code"}),d.jsx("option",{value:"system",children:"System default"})]})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Source control"}),d.jsx("p",{className:"muted",children:"Sign in with OAuth to list every repository the account can access. Tokens stay in ~/.loadpath/settings.json. A classic PAT still works if you prefer not to register an OAuth app."}),d.jsxs("div",{className:"scm-login","data-testid":"scm-github",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitHub"}),d.jsx("p",{className:"muted",children:C.github_token_set?C.github_user?`Signed in as @${String(C.github_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.github_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-github-disconnect",onClick:()=>void yt("github"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-github-login",disabled:!!dt||!C.github_oauth_ready,onClick:()=>void hr(),children:dt?"Waiting for GitHub…":"Sign in with GitHub"})})]}),dt?d.jsxs("p",{className:"oauth-code","data-testid":"github-user-code",children:["Enter ",d.jsx("code",{children:dt.user_code})," at GitHub if the browser did not fill it in."]}):null,C.github_oauth_ready?null:d.jsx("p",{className:"muted",children:"Sign-in needs a GitHub OAuth App with Device Flow enabled. Set LOADPATH_GITHUB_CLIENT_ID or paste the client ID below."}),d.jsx("label",{htmlFor:"github_oauth_client_id",children:"GitHub OAuth client ID"}),d.jsx("input",{id:"github_oauth_client_id",name:"github_oauth_client_id","data-testid":"github-oauth-client-id",placeholder:"Ov23…",defaultValue:String(C.github_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"github_token",children:"GitHub token (optional PAT)"}),d.jsx("input",{id:"github_token",name:"github_token",type:"password",placeholder:"ghp_…",autoComplete:"off"}),d.jsx("label",{htmlFor:"github_host",children:"GitHub host (Enterprise)"}),d.jsx("input",{id:"github_host",name:"github_host","data-testid":"github-host",placeholder:"github.com",defaultValue:String(C.github_host||""),autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-gitlab",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitLab"}),d.jsx("p",{className:"muted",children:C.gitlab_token_set?C.gitlab_user?`Signed in as @${String(C.gitlab_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.gitlab_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-gitlab-disconnect",onClick:()=>void yt("gitlab"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-gitlab-login",disabled:Wn||!C.gitlab_oauth_ready,onClick:()=>void ko(),children:Wn?"Waiting for GitLab…":"Sign in with GitLab"})})]}),d.jsx("label",{htmlFor:"gitlab_host",children:"GitLab host"}),d.jsx("input",{id:"gitlab_host",name:"gitlab_host","data-testid":"gitlab-host",placeholder:"gitlab.com",defaultValue:String(C.gitlab_host||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_id",children:"GitLab OAuth application ID"}),d.jsx("input",{id:"gitlab_oauth_client_id",name:"gitlab_oauth_client_id","data-testid":"gitlab-oauth-client-id",defaultValue:String(C.gitlab_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_secret",children:"GitLab OAuth secret"}),d.jsx("input",{id:"gitlab_oauth_client_secret",name:"gitlab_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_token",children:"GitLab token (optional PAT)"}),d.jsx("input",{id:"gitlab_token",name:"gitlab_token",type:"password",placeholder:"glpat-…",autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-bitbucket",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"Bitbucket"}),d.jsx("p",{className:"muted",children:C.bitbucket_token_set?C.bitbucket_user?`Signed in as ${String(C.bitbucket_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.bitbucket_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-bitbucket-disconnect",onClick:()=>void yt("bitbucket"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-bitbucket-login",disabled:Vn||!C.bitbucket_oauth_ready,onClick:()=>void di(),children:Vn?"Waiting for Bitbucket…":"Sign in with Bitbucket"})})]}),C.bitbucket_oauth_ready?null:d.jsxs("p",{className:"muted",children:["Sign-in needs a Bitbucket OAuth consumer (key + secret). Callback URL:"," ",d.jsx("code",{children:"/api/oauth/bitbucket/callback"})," on this app origin."]}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_id",children:"Bitbucket OAuth key"}),d.jsx("input",{id:"bitbucket_oauth_client_id",name:"bitbucket_oauth_client_id","data-testid":"bitbucket-oauth-client-id",defaultValue:String(C.bitbucket_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_secret",children:"Bitbucket OAuth secret"}),d.jsx("input",{id:"bitbucket_oauth_client_secret",name:"bitbucket_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_token",children:"Bitbucket token (optional app password)"}),d.jsx("input",{id:"bitbucket_token",name:"bitbucket_token",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_username",children:"Bitbucket username (app passwords)"}),d.jsx("input",{id:"bitbucket_username",name:"bitbucket_username",defaultValue:String(C.bitbucket_username||"")})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Residual AI"}),d.jsx("label",{htmlFor:"ai_provider",children:"Provider"}),d.jsxs("select",{id:"ai_provider",name:"ai_provider",defaultValue:String(((an=C.ai)==null?void 0:an.provider)||"none"),children:[d.jsx("option",{value:"none",children:"none (graph only)"}),d.jsx("option",{value:"anthropic",children:"Anthropic"}),d.jsx("option",{value:"openai",children:"OpenAI"}),d.jsx("option",{value:"grok",children:"Grok / xAI"}),d.jsx("option",{value:"deepseek",children:"DeepSeek"}),d.jsx("option",{value:"cursor",children:"Cursor-compatible (OpenAI protocol)"}),d.jsx("option",{value:"ollama",children:"Ollama local"})]}),d.jsx("label",{htmlFor:"ai_api_key",children:"API key"}),d.jsx("input",{id:"ai_api_key",name:"ai_api_key",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"ai_model",children:"Model"}),d.jsx("input",{id:"ai_model",name:"ai_model","data-testid":"ai-model",placeholder:"optional override",defaultValue:String(((ln=C.ai)==null?void 0:ln.model)||"")}),d.jsx("label",{htmlFor:"ai_base_url",children:"Base URL"}),d.jsx("input",{id:"ai_base_url",name:"ai_base_url","data-testid":"ai-base-url",placeholder:"optional, OpenAI-compatible",defaultValue:String(((un=C.ai)==null?void 0:un.base_url)||"")}),d.jsx("button",{className:"btn primary",type:"submit","data-testid":"btn-save-settings",children:"Save"})]})]})]})]}),d.jsx(x0,{open:nt,actions:Kn,onClose:()=>lt(!1)}),je?d.jsx(KN,{initialPath:o,onClose:()=>Le(!1),onSelect:P=>{if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}Le(!1),Br(P)}}):null]})}function ij({review:t,findings:r,aiNote:o,busy:s,tourIndex:a,onTour:u,onAskAi:c,onCopy:h,onPost:p,onSelect:y,onOpenFile:x,onExport:v,history:g,diff:_,onReopen:S,onWaiver:N}){var E,I,w,j,A,$,F,Y,q,re,J,te,Q,C,V,W,U;const b=[...new Set(t.confidence.reasons||[])];return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:`merge-box ${t.confidence.level}`,children:[d.jsxs("div",{className:`level ${t.confidence.level}`,children:[t.confidence.level.toUpperCase()," — ",t.title]}),b.length?d.jsx("ul",{className:"reasons",children:b.map(M=>d.jsx("li",{children:M},M))}):null,t.what_if?d.jsx("span",{className:"chip whatif","data-testid":"whatif-chip",children:"what-if"}):null,t.low_risk?d.jsx("span",{className:"chip",children:"low-risk"}):null,t.change_kinds.map(M=>d.jsx("span",{className:"chip",children:ns(M)},M)),(E=t.contract_break)!=null&&E.kind&&t.contract_break.kind!=="none"?d.jsxs("span",{className:`chip ${t.contract_break.kind==="breaking"?"blocker":""}`,"data-testid":"contract-kind",children:["contract ",t.contract_break.kind]}):null]}),d.jsxs("div",{className:"metrics",children:[d.jsxs("div",{className:"metric",children:[d.jsxs("div",{className:"n",children:[t.confidence.covered_sinks,"/",t.confidence.sinks]}),d.jsx("div",{className:"l",children:"Sinks tested"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:r.length}),d.jsx("div",{className:"l",children:"Findings"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:t.residuals.length}),d.jsx("div",{className:"l",children:"Residuals"})]})]}),d.jsx("pre",{className:"headline",children:t.headline}),(t.checklist||[]).length?d.jsxs("details",{className:"section",open:!0,"data-testid":"merge-checklist",children:[d.jsxs("summary",{children:["Merge checklist"," ",d.jsx("span",{className:"count",children:(t.checklist||[]).filter(M=>M.status==="todo").length})]}),(t.checklist||[]).map(M=>d.jsxs("div",{className:`check-item ${M.status}`,children:[d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.status}`,children:M.status}),M.title]}),M.detail?d.jsx("div",{className:"why",children:M.detail}):null,M.body?d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body||"")},children:"Copy test"}):null,M.kind==="finding"&&M.status==="todo"&&M.rule?d.jsx("button",{type:"button",className:"btn",onClick:()=>N(M.rule,M.node_id),children:"Waive in loadpath.yml"}):null]},M.id))]}):null,t.index?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Index ",d.jsx("span",{className:"count",children:t.index.counts.nodes})]}),d.jsxs("div",{className:"muted",children:["Walked ",t.index.counts.nodes," nodes / ",t.index.counts.edges," edges",t.index.reindex_skipped?" from an unchanged index":t.index.reindexed?" after an incremental refresh":" from the existing index",t.index.django_boot&&t.index.django_boot!=="off"?` · Django boot ${t.index.django_boot}`:"",(I=t.workspace)!=null&&I.three_dot?" · three-dot range":""]})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Read this ",d.jsx("span",{className:"count",children:t.read_order.length})]}),t.read_order.map((M,D)=>d.jsxs("div",{className:D===a?"read-item tour-current":"read-item",children:[d.jsxs("button",{type:"button",className:"linkish file",onClick:()=>u(D),children:[D+1,". ",M.path]}),d.jsx("div",{className:"why",children:M.why}),d.jsx("button",{type:"button",className:"btn",onClick:()=>x(M.path),children:"Open"})]},M.path)),t.read_order.length>0?d.jsxs("div",{className:"btn-row tour-row",children:[d.jsx("button",{type:"button",className:"btn","data-testid":"btn-tour-prev",disabled:a<=0,onClick:()=>u(Math.max(0,a-1)),children:"Previous"}),d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-tour-next",disabled:a>=t.read_order.length-1,onClick:()=>u(Math.min(t.read_order.length-1,a+1)),children:"Next in read order"}),d.jsxs("span",{className:"muted",children:[a+1,"/",t.read_order.length]})]}):null]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Clusters ",d.jsx("span",{className:"count",children:t.clusters.length})]}),t.clusters.map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:M.title})," — ",M.files.join(", ")]},M.id))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Architecture ",d.jsx("span",{className:"count",children:r.length})]}),r.length===0?d.jsx("div",{className:"muted",children:t.architecture_note}):r.map(M=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.severity}`,children:M.severity}),M.message]})},M.rule+M.message))]}),d.jsx(Im,{cards:t.deepening}),(j=(w=t.contract_break)==null?void 0:w.reasons)!=null&&j.length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Contract ",d.jsx("span",{className:"count",children:t.contract_break.kind})]}),t.contract_break.reasons.map(M=>d.jsx("div",{className:"muted",children:M},M)),($=(A=t.contract_break.sides)==null?void 0:A.rows)!=null&&$.length?d.jsxs("table",{className:"type-table","data-testid":"contract-sides",children:[d.jsx("thead",{children:d.jsxs("tr",{children:[d.jsx("th",{children:"Field"}),d.jsx("th",{children:"Serializer"}),d.jsx("th",{children:"Zod"}),d.jsx("th",{children:"GraphQL"})]})}),d.jsx("tbody",{children:t.contract_break.sides.rows.map(M=>d.jsxs("tr",{className:M.status,children:[d.jsx("td",{children:M.field}),d.jsx("td",{children:M.serializer?"yes":"—"}),d.jsx("td",{children:M.zod?"yes":"—"}),d.jsx("td",{children:M.graphql?"yes":"—"})]},M.field))})]}):null]}):null,(F=t.auth)!=null&&F.note?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Auth"}),d.jsx("div",{className:"muted",children:t.auth.note}),(t.auth.missing_permissions||[]).map(M=>d.jsxs("div",{className:"finding",children:[d.jsx("span",{className:"chip warning",children:"missing"}),M.name]},M.id))]}):null,(t.suggested_tests||[]).length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Suggested tests ",d.jsx("span",{className:"count",children:(Y=t.suggested_tests)==null?void 0:Y.length})]}),(t.suggested_tests||[]).map(M=>d.jsxs("div",{className:"residual",children:[d.jsx("strong",{children:M.title}),d.jsx("pre",{className:"headline",children:M.body}),d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body)},children:"Copy sketch"})]},M.title))]}):null,(q=t.trend)!=null&&q.note?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Confidence trend"}),d.jsx("div",{className:"muted",children:t.trend.note}),(t.trend.points||[]).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[M.level," · ",ic(M.created_at),M.sinks!=null?` · ${M.sinks} sinks`:""]},M.id))]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Residual ",d.jsx("span",{className:"count",children:t.residuals.length})]}),d.jsx("p",{className:"muted",children:"AI is only used here, on what the graph could not close."}),t.residuals.map(M=>d.jsx("div",{className:"residual muted",children:M},M))]}),g.length?d.jsxs("details",{className:"section","data-testid":"review-history",children:[d.jsxs("summary",{children:["History ",d.jsx("span",{className:"count",children:g.length})]}),_?d.jsx("div",{className:"muted",children:_.note}):null,g.slice(0,12).map(M=>d.jsxs("button",{type:"button",className:M.id===t.id?"history-item current":"history-item",onClick:()=>S(M.id),children:[d.jsx("span",{className:`chip ${M.level||""}`,children:M.level||"walk"}),M.title||M.id.slice(0,8),d.jsx("span",{className:"muted",children:M.created_at?ic(M.created_at):""})]},M.id))]}):null,(J=(re=t.evolution)==null?void 0:re.notes)!=null&&J.length||(Q=(te=t.evolution)==null?void 0:te.hotspots)!=null&&Q.some(M=>M.commits)?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Churn & coupling"}),(((C=t.evolution)==null?void 0:C.notes)||[]).map(M=>d.jsx("div",{className:"muted",children:M},M)),(((V=t.evolution)==null?void 0:V.hotspots)||[]).filter(M=>M.commits).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("span",{className:"file",children:M.path})," — ",M.commits," commits, bus factor ",M.bus_factor]},M.path))]}):null,d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:s,onClick:c,children:"Ask configured model"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-copy-markdown",onClick:h,children:"Copy markdown"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-export-html",onClick:v,children:"Save HTML"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-post-comment",disabled:s||!!t.what_if,title:t.what_if?"Hypothetical walks are not posted to a pull request":void 0,onClick:p,children:"Post to PR"})]}),o?d.jsx("pre",{className:"headline",children:o}):null,d.jsx("div",{className:"kicker",children:"Reviewers"}),d.jsx("div",{className:"muted",children:t.suggested_reviewers.join(", ")||"—"}),(W=t.codeowners_reviewers)!=null&&W.length?d.jsxs("div",{className:"muted",children:["CODEOWNERS: ",t.codeowners_reviewers.join(", ")]}):null,(U=t.knowledge_owners)!=null&&U.length?d.jsxs("div",{className:"muted",children:["Knowledge: ",t.knowledge_owners.join(", ")]}):null]})}function sj({architecture:t,busy:r,onReindex:o,onReview:s,onSelect:a,config:u,health:c,onSaveConfig:h,onWaiver:p}){var x;const y=t.findings.filter(v=>!v.waived);return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"merge-box high",children:[d.jsxs("div",{className:"level high",children:["INDEXED — ",t.counts.nodes," nodes"]}),d.jsxs("div",{className:"muted",style:{marginTop:8},children:[t.indexed_at?`Last index ${ic(t.indexed_at)}`:"Indexed",t.incremental?" · incremental":" · full",t.stale?" · stale":"",t.django_boot&&t.django_boot!=="off"?` · Django boot ${t.django_boot}`:""]}),d.jsxs("span",{className:"chip",children:[t.counts.edges," edges"]}),t.has_config?d.jsx("span",{className:"chip",children:"loadpath.yml"}):null]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Bounded contexts"}),Object.values(t.contexts).map(v=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v.name})," — ",(v.django_apps||[]).join(", ")||"no apps"," ·"," ",(v.owners||[]).join(", ")||"unowned"]},v.name))]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Rules ",d.jsx("span",{className:"count",children:(t.rules||[]).length})]}),(t.rules||[]).map(v=>d.jsx("div",{className:"muted",children:v},v))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Findings ",d.jsx("span",{className:"count",children:y.length})]}),y.length===0?d.jsx("div",{className:"muted",children:"No architecture rule hits on the full graph."}):y.map(v=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>v.node_id&&a(v.node_id),children:[d.jsx("span",{className:`chip ${v.severity}`,children:v.severity}),v.message]})},v.rule+v.message))]}),d.jsx(Im,{cards:t.deepening}),(x=c==null?void 0:c.points)!=null&&x.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"architecture-health",children:[d.jsxs("summary",{children:["Health over time ",d.jsx("span",{className:"count",children:c.points.length})]}),d.jsx("div",{className:"sparkline","aria-hidden":"true",children:c.points.map(v=>d.jsx("i",{className:v.level||"",title:`${v.level} · ${v.findings} findings`,style:{height:`${8+Math.min(24,(v.findings||0)*4)}px`}},v.id||v.created_at))}),Object.entries(c.contexts).map(([v,g])=>{var _;return d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v})," — last ",((_=g[g.length-1])==null?void 0:_.findings)??0," findings"]},v)})]}):null,u?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"loadpath.yml"}),d.jsx(w0,{config:u,busy:r,onSave:h,onWaiver:p})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Types"}),d.jsx("table",{className:"type-table",children:d.jsx("tbody",{children:Object.entries(t.type_counts||{}).sort((v,g)=>g[1]-v[1]).slice(0,12).map(([v,g])=>d.jsxs("tr",{children:[d.jsx("td",{children:li(v)}),d.jsx("td",{children:g})]},v))})})]}),d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:r,onClick:o,"data-testid":"btn-full-reindex",children:"Full reindex"}),d.jsx("button",{type:"button",className:"btn primary",disabled:r,onClick:s,children:"Review against this index"})]})]})}function Im({cards:t}){const r=t||[];return r.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"deepening-list",children:[d.jsxs("summary",{children:["Depth ",d.jsx("span",{className:"count",children:r.length})]}),d.jsx("p",{className:"muted",children:"Deepening opportunities: more behaviour behind a smaller interface, at a real seam."}),r.map(o=>d.jsxs("div",{className:"finding","data-testid":"deepening-card",children:[d.jsx("span",{className:`chip ${o.strength}`,children:_0(o.strength)}),o.top?d.jsx("span",{className:"chip",children:"top"}):null,d.jsx("strong",{children:o.title}),d.jsx("div",{className:"why",children:o.message}),o.deletion_test?d.jsxs("div",{className:"muted",children:["Deletion test: ",o.deletion_test]}):null,o.before&&o.after?d.jsxs("div",{className:"muted",children:[o.before," → ",o.after]}):null]},o.rule+o.title))]}):null}Pm(Mm());m0.createRoot(document.getElementById("root")).render(d.jsx(L.StrictMode,{children:d.jsx(oj,{})}));export{Kk as L,uj as a,aj as c,d as j,lj as l,L as r,li as t}; + M${Y.x},${Y.y}h${Y.width}v${Y.height}h${-Y.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}_m.displayName="MiniMap";const zk=L.memo(_m),Dk=t=>r=>t?`${Math.max(1/r.transform[2],1)}`:void 0,Ok={[oi.Line]:"right",[oi.Handle]:"bottom-right"};function Fk({nodeId:t,position:r,variant:o=oi.Handle,className:s,style:a=void 0,children:u,color:c,minWidth:h=10,minHeight:p=10,maxWidth:y=Number.MAX_VALUE,maxHeight:x=Number.MAX_VALUE,keepAspectRatio:v=!1,resizeDirection:g,autoScale:_=!0,shouldResize:S,onResizeStart:N,onResize:b,onResizeEnd:E}){const I=Qg(),w=typeof t=="string"?t:I,j=Ge(),A=L.useRef(null),$=o===oi.Handle,F=De(L.useCallback(Dk($&&_),[$,_]),Qe),Y=L.useRef(null),q=r??Ok[o];L.useEffect(()=>{if(!(!A.current||!w))return Y.current||(Y.current=a_({domNode:A.current,nodeId:w,getStoreItems:()=>{const{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,domNode:W}=j.getState();return{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,paneDomNode:W}},onChange:(J,te)=>{const{triggerNodeChanges:Q,nodeLookup:C,parentLookup:V,nodeOrigin:W}=j.getState(),U=[],M={x:J.x,y:J.y},D=C.get(w);if(D&&D.expandParent&&D.parentId){const H=D.origin??W,R=J.width??D.measured.width??0,z=J.height??D.measured.height??0,ne={id:D.id,parentId:D.parentId,rect:{width:R,height:z,..._g({x:J.x??D.position.x,y:J.y??D.position.y},{width:R,height:z},D.parentId,C,H)}},oe=$c([ne],C,V,W);U.push(...oe),M.x=J.x?Math.max(H[0]*R,J.x):void 0,M.y=J.y?Math.max(H[1]*z,J.y):void 0}if(M.x!==void 0&&M.y!==void 0){const H={id:w,type:"position",position:{...M}};U.push(H)}if(J.width!==void 0&&J.height!==void 0){const R={id:w,type:"dimensions",resizing:!0,setAttributes:g?g==="horizontal"?"width":"height":!0,dimensions:{width:J.width,height:J.height}};U.push(R)}for(const H of te){const R={...H,type:"position"};U.push(R)}Q(U)},onEnd:({width:J,height:te})=>{const Q={id:w,type:"dimensions",resizing:!1,dimensions:{width:J,height:te}};j.getState().triggerNodeChanges([Q])}})),Y.current.update({controlPosition:q,boundaries:{minWidth:h,minHeight:p,maxWidth:y,maxHeight:x},keepAspectRatio:v,resizeDirection:g,onResizeStart:N,onResize:b,onResizeEnd:E,shouldResize:S}),()=>{var J;(J=Y.current)==null||J.destroy()}},[q,h,p,y,x,v,N,b,E,S]);const re=q.split("-");return d.jsx("div",{className:ot(["react-flow__resize-control","nodrag",...re,o,s]),ref:A,style:{...a,scale:F,...c&&{[$?"backgroundColor":"borderColor"]:c}},children:u})}L.memo(Fk);const Hk={"arch.context":0,"django.app":0,"django.route":1,"django.websocket_route":1,"fastapi.route":1,"django.url_name":2,"django.view":3,"django.viewset_action":3,"django.permission":3,"django.throttle":3,"django.serializer":4,"django.form":4,"graphql.type":4,"fastapi.model":4,"django.serializer_field":5,"django.service":5,"graphql.field":5,"django.model":6,"django.field":7,"django.relation":7,"django.task":8,"django.receiver":8,"django.signal":8,"django.test":8,"django.migration_op":8,"django.admin":8,"django.management_command":8,"django.consumer":8,"django.cache_key":8,"django.feature_flag":8,"django.side_effect":8,"openapi.path":9,"graphql.operation":9,"react.api_client":10,"django.htmx":10,"react.query_key":11,"react.hook":11,"react.feature":11,"react.route":12,"react.page":12,"react.server_action":12,"django.template":12,"react.component":13,"react.context":13,"react.form_schema":14,"react.test":14};function si(t){return Hk[t]??8}const zn=208,Dr=64,ai=88,Dc=28,Bk=8;function Vk(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function Sm(t,r=[]){const o=new Map;if(!t.length)return o;const s=new Map;for(const w of t){const j=si(w.type),A=s.get(j)??[];A.push(w),s.set(j,A)}const u=[...s.keys()].sort((w,j)=>w-j).map(w=>[...s.get(w)??[]].sort((j,A)=>j.name.localeCompare(A.name)||j.id.localeCompare(A.id))),c=new Set(t.map(w=>w.id)),h=new Map,p=new Map;for(const w of t)h.set(w.id,[]),p.set(w.id,[]);for(const w of r)!c.has(w.src)||!c.has(w.dst)||w.src===w.dst||(p.get(w.src).push(w.dst),h.get(w.dst).push(w.src));const y=new Map;u.forEach((w,j)=>{for(const A of w)y.set(A.id,j)});const x=new Map,v=()=>{for(const w of u)w.forEach((j,A)=>x.set(j.id,A))};v();const g=(w,j)=>{const A=w.map(($,F)=>{const Y=j($.id).map(re=>x.get(re)).filter(re=>re!==void 0),q=Vk(Y);return{n:$,bary:Number.isNaN(q)?F:q,name:$.name,id:$.id}});return A.sort(($,F)=>$.bary-F.bary||$.name.localeCompare(F.name)||$.id.localeCompare(F.id)),A.map($=>$.n)},_=w=>j=>y.get(j)===w;for(let w=0;w(h.get(A)??[]).filter(_(j-1))),v();for(let j=u.length-2;j>=0;j--)u[j]=g(u[j],A=>(p.get(A)??[]).filter(_(j+1))),v()}const S=zn+ai,N=Dr+Dc,b=Math.max(...u.map(w=>w.length),1),E=[];let I=0;for(let w=0;wY.id)),A=new Set((u[w+1]??[]).map(Y=>Y.id));let $=0;if(A.size)for(const Y of r)j.has(Y.src)&&A.has(Y.dst)&&($+=1);const F=Math.min(120,Math.max(0,($-2)*12));I+=S+F}return u.forEach((w,j)=>{const A=(b-w.length)*N/2;w.forEach(($,F)=>{o.set($.id,{x:E[j]??0,y:A+F*N})})}),o}const xc=[{id:"layers",label:"Architecture layers"},{id:"flow",label:"Edge flow"},{id:"radial",label:"Radial"},{id:"grid",label:"Compact grid"}],Wk=new Set(xc.map(t=>t.id)),km="loadpath.graphLayout",Uk=8,Gk=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","openapi.path","django.consumer","django.websocket_route","django.template","graphql.operation","fastapi.route"]),Nm=90,Yk=new Set(["django.field","django.serializer_field","django.relation","django.test","react.test","graphql.field","django.url_name","django.throttle"]),wp={"arch.context":"#edf2f4","django.app":"#8d99ae","django.route":"#4cc9f0","django.url_name":"#4cc9f0","django.view":"#4895ef","django.viewset_action":"#4361ee","django.permission":"#7b8cde","django.serializer":"#f4a261","django.form":"#e9c46a","django.serializer_field":"#e9c46a","django.service":"#90be6d","django.model":"#2a9d8f","django.field":"#8ac926","django.task":"#e76f51","django.receiver":"#e85d04","django.signal":"#f4a261","django.test":"#6c757d","django.admin":"#adb5bd","django.migration_op":"#9d4edd","django.consumer":"#e76f51","django.websocket_route":"#4cc9f0","django.template":"#c77dff","django.htmx":"#ff6b6b","django.cache_key":"#6c757d","django.feature_flag":"#f4a261","django.side_effect":"#e85d04","graphql.type":"#00bbf9","graphql.operation":"#00bbf9","fastapi.route":"#4cc9f0","fastapi.model":"#f4a261","openapi.path":"#00bbf9","react.api_client":"#ff6b6b","react.query_key":"#adb5bd","react.hook":"#7b2cbf","react.feature":"#9d4edd","react.route":"#c77dff","react.page":"#c77dff","react.server_action":"#e76f51","react.component":"#9d4edd","react.form_schema":"#ffd166","react.test":"#6c757d"},Xk=Math.PI*(3-Math.sqrt(5)),jm=220,qk=26,Kk={0:"context",1:"routes",2:"url names",3:"views",4:"serializers",5:"services",6:"models",7:"fields",8:"jobs / signals",9:"openapi",10:"api client",11:"hooks",12:"pages",13:"components",14:"forms / tests"};function bm(t){return t.startsWith("react.")?"react":t.startsWith("openapi.")||t.startsWith("graphql.")||t.startsWith("fastapi.")?"stitch":t.startsWith("arch.")?"arch":"django"}function aj(t){return wp[t]?wp[t]:t.startsWith("react.")?"#9d4edd":t.startsWith("openapi.")?"#00bbf9":"#4a5568"}function Qk(t){return t>=Nm?"3d":"2d"}function Zk(t){return t>=Nm?"overview":"full"}function Jk(t,r,o=1){const s=new Set([t]);let a=new Set([t]);for(let u=0;uo.families.has(bm(h.type)));o.detail==="overview"&&(s=s.filter(h=>!Yk.has(h.type)));const a=new Set(s.map(h=>h.id)),u=r.filter(h=>a.has(h.src)&&a.has(h.dst)),c=o.focusId?Jk(o.focusId,u,1):new Set;if(o.neighborhoodOnly&&o.focusId&&c.size){s=s.filter(p=>c.has(p.id));const h=new Set(s.map(p=>p.id));return{nodes:s,edges:u.filter(p=>h.has(p.src)&&h.has(p.dst)),neighborIds:c}}return{nodes:s,edges:u,neighborIds:c}}function tN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>`${s.name} ${s.qualified_name} ${s.type} ${s.file_path||""} ${s.context||""}`.toLowerCase().includes(o)).slice(0,24):[]}function nN(t,r,o,s){const a=new Set(t.map(N=>N.id));if(!a.has(o))return{nodeIds:new Set,edgeIds:new Set};const u=new Map,c=new Map;for(const N of r){if(!a.has(N.src)||!a.has(N.dst))continue;const b=u.get(N.src)??[];b.push({dst:N.dst,id:N.id}),u.set(N.src,b);const E=c.get(N.dst)??[];E.push({src:N.src,id:N.id}),c.set(N.dst,E)}const h=new Set(t.filter(N=>Gk.has(N.type)).map(N=>N.id)),p=h.size?h:a,y=new Set,x=[o];for(;x.length;){const N=x.pop();if(!y.has(N)){y.add(N);for(const b of u.get(N)??[])y.has(b.dst)||x.push(b.dst)}}const v=new Set([o]),g=[...p].filter(N=>y.has(N)),_=new Set(g);for(;g.length;){const N=g.pop();v.add(N);for(const b of c.get(N)??[])y.has(b.src)&&!_.has(b.src)&&(_.add(b.src),g.push(b.src))}const S=new Set;for(const N of r)v.has(N.src)&&v.has(N.dst)&&S.add(N.id);return{nodeIds:v,edgeIds:S}}function lj(t){const r=new Map;for(const s of t){const a=si(s.type),u=r.get(a)??[];u.push(s),r.set(a,u)}const o=new Map;for(const[s,a]of r){a.sort((c,h)=>c.name.localeCompare(h.name));const u=s*jm;a.forEach((c,h)=>{if(a.length===1){o.set(c.id,{x:u,y:0,z:0});return}const p=qk*Math.sqrt(h+1),y=h*Xk;o.set(c.id,{x:u,y:p*Math.cos(y),z:p*Math.sin(y)})})}return o}function uj(t){const r=new Map;for(const o of t){const s=si(o.type);r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>o[0]-s[0]).map(([o,s])=>({layer:o,x:o*jm,count:s}))}function rN(){try{if(typeof localStorage>"u")return"layers";const t=localStorage.getItem(km);return t&&Wk.has(t)?t:"layers"}catch{return"layers"}}function oN(t){try{if(typeof localStorage>"u")return;localStorage.setItem(km,t)}catch{}}function iN(t){return t==="layers"||t==="flow"}function sN(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function ts(t,r){return t.name.localeCompare(r.name)||t.id.localeCompare(r.id)}function aN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.flat().map(S=>S.id)),a=new Map,u=new Map;for(const S of t.flat())a.set(S.id,[]),u.set(S.id,[]);for(const S of r)!s.has(S.src)||!s.has(S.dst)||S.src===S.dst||(u.get(S.src).push(S.dst),a.get(S.dst).push(S.src));const c=new Map;t.forEach((S,N)=>{for(const b of S)c.set(b.id,N)});const h=new Map,p=()=>{for(const S of t)S.forEach((N,b)=>h.set(N.id,b))};p();const y=(S,N)=>{const b=S.map((E,I)=>{const w=N(E.id).map(A=>h.get(A)).filter(A=>A!==void 0),j=sN(w);return{n:E,bary:Number.isNaN(j)?I:j,name:E.name,id:E.id}});return b.sort((E,I)=>E.bary-I.bary||E.name.localeCompare(I.name)||E.id.localeCompare(I.id)),b.map(E=>E.n)},x=S=>N=>c.get(N)===S;for(let S=0;S(a.get(b)??[]).filter(x(N-1))),p();for(let N=t.length-2;N>=0;N--)t[N]=y(t[N],b=>(u.get(b)??[]).filter(x(N+1))),p()}const v=zn+ai,g=Dr+Dc,_=Math.max(...t.map(S=>S.length),1);return t.forEach((S,N)=>{const b=(_-S.length)*g/2;S.forEach((E,I)=>{o.set(E.id,{x:N*v,y:b+I*g})})}),o}function lN(t,r){const o=new Set(t.map(h=>h.id)),s=Math.max(t.length-1,0),a=new Map;for(const h of t)a.set(h.id,0);for(let h=0;h(a.get(y.dst)||0)&&(a.set(y.dst,x),p=!0)}if(!p)break}const u=new Map;for(const h of t){const p=a.get(h.id)||0,y=u.get(p)??[];y.push(h),u.set(p,y)}const c=[...u.keys()].sort((h,p)=>h-p).map(h=>(u.get(h)??[]).sort(ts));return aN(c,r)}function uN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.map(g=>g.id)),a=new Map,u=new Map;for(const g of t)a.set(g.id,[]),u.set(g.id,0);for(const g of r)!s.has(g.src)||!s.has(g.dst)||g.src===g.dst||(a.get(g.src).push(g.dst),a.get(g.dst).push(g.src),u.set(g.src,(u.get(g.src)||0)+1),u.set(g.dst,(u.get(g.dst)||0)+1));const c=[...t].sort((g,_)=>(u.get(_.id)||0)-(u.get(g.id)||0)||ts(g,_))[0]??t[0],h=new Map,p=[[c]];h.set(c.id,0);const y=[c];for(;y.length;){const g=y.shift(),_=h.get(g.id)||0,S=(a.get(g.id)??[]).map(N=>t.find(b=>b.id===N)).filter(N=>!!N).sort(ts);for(const N of S){if(h.has(N.id))continue;h.set(N.id,_+1);const b=p[_+1]??[];b.push(N),p[_+1]=b,y.push(N)}}const x=t.filter(g=>!h.has(g.id)).sort(ts);x.length&&p.push(x);const v=zn+32;return p.forEach((g,_)=>{if(_===0&&g.length===1){o.set(g[0].id,{x:0,y:0});return}const S=Math.max(_*(zn+ai),g.length<=1?zn:g.length*v/(2*Math.PI));g.forEach((N,b)=>{const E=-Math.PI/2+2*Math.PI*b/g.length;o.set(N.id,{x:Math.cos(E)*S,y:Math.sin(E)*S})})}),o}function cN(t){const r=new Map,o=[...t].sort((c,h)=>si(c.type)-si(h.type)||ts(c,h)),s=Math.max(1,Math.ceil(Math.sqrt(o.length))),a=zn+ai,u=Dr+Dc;return o.forEach((c,h)=>{r.set(c.id,{x:h%s*a,y:Math.floor(h/s)*u})}),r}function dN(t,r=[],o="layers"){return o==="flow"?lN(t,r):o==="radial"?uN(t,r):o==="grid"?cN(t):Sm(t,r)}const Ia=16,fN=12,hN=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","django.throttle","django.admin","django.management_command","openapi.path","django.consumer","django.websocket_route","django.template","django.cache_key","django.feature_flag","django.side_effect","graphql.operation","fastapi.route"]),pN=new Set(["django.serializer","django.serializer_field","django.form","openapi.path","react.form_schema","django.route","graphql.type","graphql.field","graphql.operation","fastapi.model","fastapi.route"]),_p={"arch.context":"Ownership boundary from loadpath.yml — the context this code belongs to.","django.app":"Django app package that owns models, views, and jobs.","django.route":"HTTP URL that publishes a view. A sink: this is where a change becomes a public request.","django.url_name":"Named URL used by reverse() / {% url %} lookups.","django.view":"Request handler (class-based view, function view, or ViewSet).","django.viewset_action":"One ViewSet action (list, create, retrieve, update, destroy).","django.permission":"Auth gate on a view — who is allowed to hit this path.","django.throttle":"Rate-limit class attached to a view.","django.serializer":"Request/response contract: which fields go in and come out.","django.form":"Django form or django-filter FilterSet — the typed input contract.","django.serializer_field":"One field on a serializer or form — the typed slot on the contract.","django.service":"Internal service or use-case. Work that is not itself an HTTP sink.","django.model":"ORM model. Schema and relations live here.","django.field":"Model column. Type, indexes, and relations are the contract of the table.","django.relation":"Model-to-model relation (FK / M2M / O2O).","django.task":"Celery or Dramatiq job. Once enqueued, this is a sink.","django.receiver":"Signal handler that runs after a model event.","django.signal":"Django signal that receivers subscribe to.","django.test":"Backend test that mentions symbols on this path.","django.admin":"Django admin class for a model.","django.migration_op":"Schema migration operation (CreateModel, AlterField, …).","django.management_command":"manage.py command — an operational sink.","django.consumer":"Django Channels WebSocket/HTTP consumer. A sink once a client connects.","django.websocket_route":"ASGI WebSocket URL. A sink: this is where a change becomes a live connection.","django.template":"Django template. HTML (and HTMX) the server renders.","django.htmx":"HTMX call from a template to a URL — another published seam.","django.cache_key":"Cache get/set key. Invalidation is part of the load path.","django.feature_flag":"Feature flag checked on this path. The change may be dark-launched.","django.side_effect":"transaction.on_commit (or similar) side effect that runs after the request commits.","graphql.type":"GraphQL object/input type — a published contract.","graphql.field":"One field on a GraphQL type.","graphql.operation":"GraphQL query, mutation, or subscription. A published contract and a sink.","fastapi.route":"FastAPI path operation sitting next to Django in this repo.","fastapi.model":"Pydantic response/request model — the FastAPI contract.","openapi.path":"Generated OpenAPI operation. The typed HTTP contract between stacks.","react.api_client":"Frontend fetch or generated client call to an API path.","react.query_key":"React Query cache key. Invalidation and reads share this name.","react.hook":"Data hook wrapping query or mutation calls.","react.feature":"Frontend feature module (folder).","react.route":"Client-side route. A sink: this is a URL the user can open.","react.page":"Page or screen component rendered by a route.","react.server_action":"Next.js Server Action. A sink: the mutation runs on the server.","react.component":"UI component.","react.form_schema":"Zod (or similar) schema — typed form inputs on the client.","react.test":"Frontend test covering a page, hook, or component.","react.context":"React context provider."},gN={field_type:"Type",fields:"Fields",form_fields:"Form fields",permissions:"Permissions",throttles:"Throttles",authentication:"Authentication",pagination:"Pagination",filterset:"Filterset",bases:"Extends",on_delete:"on_delete",related_name:"related_name",unique:"Unique",db_index:"Indexed",relation:"Relation field",looks_idempotent_on_pk:"Idempotent on pk",broker:"Broker",route:"Route",url_name:"URL name",view:"View",include:"Includes",mounted_at:"Mounted at",full_path:"Full path",method:"Method",path:"Path",operation_id:"Operation",raw:"URL",kind:"Schema",exclude:"Excludes",queryset_in_serializer:"Queryset in serializer",get_queryset:"Custom get_queryset",get_serializer_class:"Dynamic serializer",dynamic:"Dynamic",fbv:"Function view",next_app:"Next.js App Router",next_pages:"Next.js Pages Router",next_kind:"Next file",next_layout:"Layout",server_action:"Server Action",typed_client:"Typed client",endpoint:"Endpoint",procedure:"Procedure",e2e:"E2E",visits:"Visits",nested_serializer:"Nested serializer",nested_serializers:"Nested serializers",method_field:"SerializerMethodField",method_fields:"Method fields",from_to_representation:"to_representation",to_representation_fields:"to_representation fields",to_representation:"Custom to_representation",serializer_classes:"get_serializer_class returns",get_serializer_class_resolved:"Serializer resolved",ninja_schema:"Ninja Schema",pydantic:"Pydantic",django_form:"Django form",mutation:"Mutation",has_error_boundary:"Error boundary",invalidation:"Cache invalidation",inferred:"Inferred stitch",generated:"Generated",shared:"Shared module",element:"Renders",model_name:"Model",field_name:"Field",op:"Operation",app:"App",feature:"Feature",from_view:"From view",mentions:"Mentions",nodeid:"Test id",task:"Task",to:"Related to",doc:"Summary",template:"Template",signal:"Signal",sender:"Sender",decorators:"Decorators",nplusone:"N+1 risk",lookups:"Lookups",null:"NULL",blank:"Blank",default:"Default",max_length:"max_length",max_digits:"max_digits",decimal_places:"decimal_places",primary_key:"Primary key",help_text:"Help text",choices:"Choices",auto_now:"auto_now",auto_now_add:"auto_now_add",basename:"Router basename",args:"Args",beat:"Beat",schedule_name:"Schedule",websocket:"WebSocket",htmx:"HTMX",blocks:"Blocks",db_table:"db_table"},Sp=["doc","field_type","method","path","operation_id","raw","route","mounted_at","full_path","url_name","view","element","fields","form_fields","exclude","nested_serializer","nested_serializers","method_fields","to_representation_fields","serializer_classes","typed_client","endpoint","procedure","visits","kind","bases","permissions","authentication","throttles","pagination","filterset","on_delete","related_name","to","unique","db_index","null","blank","default","max_length","max_digits","decimal_places","primary_key","auto_now","auto_now_add","help_text","choices","relation","nplusone","lookups","template","signal","sender","decorators","basename","args","beat","schedule_name","websocket","htmx","blocks","db_table","looks_idempotent_on_pk","broker","task","model_name","field_name","op","app","feature","from_view","include","fbv","ninja","django_form","mutation","has_error_boundary","invalidation","inferred","generated","shared","queryset_in_serializer","get_queryset","get_serializer_class","dynamic","mentions","nodeid"],kp=new Set(["referenced","placeholder","booted","line","call","from","import","local","source","file","plain_handler","string_ref","pagination_sink","match","via","generated_client","django","react","superseded_by_generated","foreign_app","imported"]),mN=new Set(["looks_idempotent_on_pk","null","blank"]),yN=new Set(["inferred","generated","mutation","fbv","ninja","filterset","next_app","next_pages","server_action","e2e","ninja_schema","pydantic","method_field","trpc"]);function vN(t){return _p[t]?_p[t]:t.startsWith("react.")?"A React node on the load path.":t.startsWith("django.")?"A Django node on the load path.":t.startsWith("openapi.")?"A stitch node between Django and React.":"A node on the architecture graph."}function xN(t,r,o){const s=new Map(r.map(g=>[g.id,g])),a=[];hN.has(t.type)&&a.push("sink"),pN.has(t.type)&&a.push("contract");const u=t.extra??{};u.inferred&&a.push("inferred"),u.generated&&a.push("generated"),u.mutation&&a.push("mutation"),u.fbv&&a.push("function view"),u.ninja&&a.push("ninja"),u.ninja_schema&&a.push("ninja schema"),u.next_app&&a.push("app router"),u.typed_client&&a.push(String(u.typed_client)),u.e2e&&a.push("e2e"),u.filterset===!0&&a.push("filterset");const c=o.filter(g=>g.dst===t.id),h=o.filter(g=>g.src===t.id),p=c.slice(0,Ia).map(g=>Ra(g,s,g.src)),y=h.slice(0,Ia).map(g=>Ra(g,s,g.dst)),x=t.file_path?`${t.file_path}${t.start_line?`:${t.start_line}`:""}`:void 0,v={type:t.type,typeLabel:ns(li(t.type)),layer:Kk[si(t.type)]??"other",purpose:vN(t.type),name:t.name,qualifiedName:t.qualified_name,file:x,context:t.context,roles:a,facts:_N(u).filter(g=>!(g.key==="app"&&g.value===t.context)),inputs:p,outputs:y,extraInputs:Math.max(0,c.length-Ia),extraOutputs:Math.max(0,h.length-Ia),degreeIn:c.length,degreeOut:h.length,inputKinds:Np(c.map(g=>Ra(g,s,g.src))),outputKinds:Np(h.map(g=>Ra(g,s,g.dst))),pathSummary:""};return v.pathSummary=wN(v),v}function Np(t){const r=new Map;for(const o of t){const s=o.edgeLabel||o.edgeType.replaceAll("_"," ");r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>s[1]-o[1]||o[0].localeCompare(s[0])).map(([o,s])=>({label:o,count:s}))}function wN(t){const r=t.inputKinds.map(s=>`${s.label} ×${s.count}`).join(", "),o=t.outputKinds.map(s=>`${s.label} ×${s.count}`).join(", ");return r&&o?`${r} → this → ${o}`:o?`this → ${o}`:r?`${r} → this`:""}function Ra(t,r,o){const s=r.get(o),a=o.includes(":")?o.slice(o.indexOf(":")+1):o;return{id:o,name:(s==null?void 0:s.name)||a,type:(s==null?void 0:s.type)||"",typeLabel:s?ns(li(s.type)):"",edgeType:t.type,edgeLabel:ns(t.type),inferred:t.confidence<.8}}function _N(t){const r=[...Sp.filter(a=>a in t),...Object.keys(t).filter(a=>!Sp.includes(a)&&!kp.has(a))],o=[],s=new Set;for(const a of r){if(s.has(a)||kp.has(a)||yN.has(a))continue;s.add(a);const u=SN(a,t[a]);u!=null&&o.push({key:a,label:gN[a]??ns(a),value:u})}return o}function SN(t,r){if(r==null)return null;if(typeof r=="boolean")return!r&&!mN.has(t)?null:r?"yes":"no";if(typeof r=="number")return String(r);if(typeof r=="string")return r.trim()||null;if(Array.isArray(r)){if(r.some(u=>u&&typeof u=="object"))return kN(t,r);const o=r.map(u=>typeof u=="string"||typeof u=="number"?String(u):"").filter(Boolean);if(!o.length)return null;const s=o.slice(0,fN),a=o.length-s.length;return a>0?`${s.join(", ")} +${a} more`:s.join(", ")}return null}function kN(t,r){const o=r.slice(0,4).map(a=>{if(t==="nplusone"){const c=String(a.queryset||"queryset"),h=Array.isArray(a.accessed)?a.accessed.join("."):"",p=a.line?` L${a.line}`:"";return h?`${c} → ${h}${p}`:`${c}${p}`}if(t==="lookups"){const c=Array.isArray(a.fields)?a.fields.join(", "):"",h=String(a.kind||"filter");return c?`${h} ${c}`:h}return Object.entries(a).filter(([,c])=>c!=null&&(typeof c=="string"||typeof c=="number")).slice(0,3).map(([c,h])=>`${c}=${h}`).join(" ")});if(!o.some(Boolean))return null;const s=r.length-o.length;return s>0?`${o.join("; ")} +${s} more`:o.join("; ")}const jp=12,bp=.2,NN=.8,qa=20,jN=Dr;function bN(t,r,o){const s=o??Sm(t,r),a=[...new Set([...s.values()].map(p=>p.x))].sort((p,y)=>p-y),u=[];for(const p of r){const y=s.get(p.src),x=s.get(p.dst);if(!y||!x)continue;const v=y.y+Dr/2,g=x.y+Dr/2;if(Math.abs(v-g)S.y0-N.y0||S.y1-N.y1||S.id.localeCompare(N.id)),x=MN(y),v=Math.max(0,...x.values())+1,g=y[0].sourceX,_=EN(a,g);for(const S of y){const N=PN(x.get(S.id)??0,v),b=g+qa+Math.max(1,_-2*qa)*N;h.set(S.id,CN(S.sourceX,S.targetX,b))}}return h}function EN(t,r){const o=r-zn,s=t.find(a=>a>o+1);return s===void 0?ai:Math.max(ai,s-r)}function CN(t,r,o){const s=r-t-2*qa;return s<1?.5:Math.min(1,Math.max(0,(o-t-qa)/s))}function MN(t){const r=[],o=new Map;for(const s of t){let a=-1;for(let u=0;ur[u]+jN){a=u;break}a<0?(a=r.length,r.push(s.y1)):r[a]=Math.max(r[a],s.y1),o.set(s.id,a)}return o}function PN(t,r){return r<=1?.5:bp+(NN-bp)*t/(r-1)}const IN=new Set,RN=L.lazy(()=>I0(()=>import("./LayeredGraph3D-Vlmu5bb6.js"),[],import.meta.url).then(t=>({default:t.LayeredGraph3D}))),TN={cheap:"var(--edge-cheap)",expensive:"var(--edge-expensive)",critical:"var(--edge-critical)"},Ka={n:ke.Top,e:ke.Right,s:ke.Bottom,w:ke.Left};function LN(t,r){const o=r.x-t.x,s=r.y-t.y;return Math.abs(o)>=Math.abs(s)?o>=0?{source:"e",target:"w"}:{source:"w",target:"e"}:s>=0?{source:"s",target:"n"}:{source:"n",target:"s"}}function AN({data:t,selected:r}){const o=(t.roles||[]).map(s=>`role-${s}`).join(" ");return d.jsxs("div",{className:["lp-node",r?"selected":"",t.dim?"dim":"",o].filter(Boolean).join(" "),children:[["n","e","s","w"].map(s=>d.jsx(ii,{id:`tgt-${s}`,type:"target",position:Ka[s],isConnectable:!1},`tgt-${s}`)),d.jsx("div",{className:"t",children:li(t.type)}),d.jsx("div",{className:"n",title:t.name,children:Ar(t.name)}),["n","e","s","w"].map(s=>d.jsx(ii,{id:`src-${s}`,type:"source",position:Ka[s],isConnectable:!1},`src-${s}`))]})}const $N={load:AN},zN=new Set(["django","react","stitch","arch"]);function DN({id:t,sourceX:r,sourceY:o,targetX:s,targetY:a,sourcePosition:u,targetPosition:c,style:h,markerEnd:p,markerStart:y,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,data:b,interactionWidth:E}){const[I,w,j]=Ya({sourceX:r,sourceY:o,sourcePosition:u,targetX:s,targetY:a,targetPosition:c,borderRadius:8,stepPosition:(b==null?void 0:b.stepPosition)??.5});return d.jsx(ws,{id:t,path:I,labelX:w,labelY:j,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,style:h,markerEnd:p,markerStart:y,interactionWidth:E})}const ON={loadstep:DN};function FN({topologyKey:t}){const{fitView:r}=ll();return L.useEffect(()=>{let o=0;const s=requestAnimationFrame(()=>{o=requestAnimationFrame(()=>{r({padding:.2,maxZoom:1.15})})});return()=>{cancelAnimationFrame(s),cancelAnimationFrame(o)}},[r,t]),null}function HN(t,r,o=null,s={}){const a=new Map(t.map(v=>[v.id,v])),u=s.layout??"layers",c=iN(u),h=dN(t,r,u),p=bN(t,r,h),y=t.map(v=>{var S;const g=((S=s.roles)==null?void 0:S[v.id])||[],_=!!s.testOverlay&&!g.includes("tested")&&!g.includes("untested")&&!g.includes("test")&&!g.includes("seed");return{id:v.id,type:"load",position:h.get(v.id)??{x:0,y:0},data:{name:v.name,type:v.type,file:v.file_path,roles:g,dim:_},selected:o===v.id,sourcePosition:ke.Right,targetPosition:ke.Left,width:zn,height:Dr,style:{width:zn,height:Dr}}}),x=r.filter(v=>a.has(v.src)&&a.has(v.dst)).map(v=>{const g=TN[v.weight]||"var(--edge-cheap)",_=!!(o&&(v.src===o||v.dst===o)),S=h.get(v.src)??{x:0,y:0},N=h.get(v.dst)??{x:0,y:0},b=c?{source:"e",target:"w"}:LN(S,N);return{id:v.id,source:v.src,target:v.dst,sourceHandle:`src-${b.source}`,targetHandle:`tgt-${b.target}`,sourcePosition:Ka[b.source],targetPosition:Ka[b.target],type:c?"loadstep":"default",animated:v.weight==="critical",data:{stepPosition:p.get(v.id)??.5},style:{stroke:g,strokeWidth:v.weight==="critical"?2.4:1.2,strokeDasharray:v.confidence<.8?"6 4":void 0},markerEnd:{type:us.ArrowClosed,width:14,height:14,color:g},label:_?v.type.replaceAll("_"," "):void 0,labelStyle:_?{fill:"var(--ink)",fontSize:10,fontWeight:600}:void 0,labelBgStyle:_?{fill:"var(--graph-bg)",fillOpacity:.92}:void 0,labelBgPadding:_?[3,5]:void 0,labelBgBorderRadius:_?4:void 0}});return{rfNodes:y,rfEdges:x}}function BN({node:t,nodes:r,edges:o,onClose:s,onWhatIf:a,onSelect:u,onOpenFile:c,pinned:h,onPin:p,onIsolate:y}){const x=xN(t,r,o);return L.useEffect(()=>{const v=g=>{g.key==="Escape"&&s()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[s]),d.jsxs("aside",{className:"inspector","data-testid":"graph-inspector",children:[d.jsxs("div",{className:"inspector-head",children:[d.jsx("div",{className:"t",children:x.typeLabel}),d.jsx("div",{className:"inspector-roles",children:x.roles.map(v=>d.jsx("span",{className:"inspector-chip",children:v},v))}),d.jsx("button",{type:"button",className:"inspector-close","data-testid":"graph-inspector-close","aria-label":"Close inspector",onClick:s,children:"×"})]}),d.jsx("div",{className:"n",children:Ar(x.name)}),d.jsx("p",{className:"inspector-purpose","data-testid":"graph-inspector-purpose",children:x.purpose}),x.context?d.jsx("div",{className:"muted",children:Ar(x.context)}):null,x.file?d.jsxs("div",{className:"file-row",children:[d.jsx("div",{className:"file",children:Ar(x.file)}),c&&t.file_path?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-open-editor",onClick:()=>c(t.file_path,t.start_line),children:"Open in editor"}):null]}):null,d.jsx("div",{className:"muted",children:Ar(x.qualifiedName)}),d.jsxs("div",{className:"muted inspector-layer",children:["layer · ",x.layer]}),d.jsxs("div",{className:"muted inspector-degree","data-testid":"graph-inspector-degree",children:[x.degreeIn," in · ",x.degreeOut," out"]}),x.pathSummary?d.jsx("p",{className:"inspector-path","data-testid":"graph-inspector-path",children:x.pathSummary}):null,x.facts.length?d.jsx("dl",{className:"inspector-facts","data-testid":"graph-inspector-facts",children:x.facts.map(v=>d.jsxs("div",{className:"inspector-fact",children:[d.jsx("dt",{children:v.label}),d.jsx("dd",{children:Ar(v.value)})]},v.key))}):null,d.jsx(Ep,{title:"Inputs",testId:"graph-inspector-inputs",links:x.inputs,extra:x.extraInputs,empty:"Nothing in this graph points here.",onSelect:u}),d.jsx(Ep,{title:"Outputs",testId:"graph-inspector-outputs",links:x.outputs,extra:x.extraOutputs,empty:"This node does not point at anything in this graph.",onSelect:u}),a?d.jsx("p",{className:"whatif-hint","data-testid":"whatif-hint",children:y?"Walks a new path from this node with no git range. Isolate (next) only hides the rest of this map.":"Walks a new path from this node with no git range — as if this changed, regardless of Base/Head."}):null,d.jsxs("div",{className:"btn-row",children:[a?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-whatif",title:"Start a hypothetical walk from this node. Does not use Base/Head.",onClick:()=>a(t.id),children:"What if this changes"}):null,y?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-isolate",title:"Hide nodes that are not on a path from here to a sink. Does not start a new walk.",onClick:()=>y(t.id),children:"Isolate path to sinks"}):null,p?d.jsx("button",{type:"button",className:h?"btn primary":"btn","data-testid":"btn-pin-node",onClick:()=>p(h?null:t.id),children:h?"Unpin":"Pin"}):null]})]})}function Ep({title:t,testId:r,links:o,extra:s,empty:a,onSelect:u}){return d.jsxs("section",{className:"inspector-section","data-testid":r,children:[d.jsxs("h3",{children:[t,d.jsx("span",{className:"count",children:o.length+s})]}),o.length?d.jsx("ul",{children:o.map((c,h)=>d.jsx("li",{children:u?d.jsxs("button",{type:"button",className:"inspector-link",onClick:()=>u(c.id),children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]}):d.jsxs(d.Fragment,{children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]})},`${c.edgeType}:${c.id}:${h}`))}):d.jsx("p",{className:"muted",children:a}),s?d.jsxs("p",{className:"muted",children:["+",s," more"]}):null]})}function nc({nodes:t,edges:r,onWhatIf:o,focusPath:s,selectedId:a,onSelect:u,nodeRoles:c,testOverlay:h=!1,isolateSource:p,onIsolate:y,repoPath:x,onOpenFile:v,pinnedId:g,onPin:_}){const[S,N]=L.useState(null),b=a!==void 0?a:S,E=ue=>{a===void 0&&N(ue),u==null||u(ue)},[I,w]=L.useState(null),[j,A]=L.useState(null),[$,F]=L.useState(()=>rN()),[Y,q]=L.useState(new Set(zN)),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState(!1),W=typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,U=I??Qk(t.length),M=j??Zk(t.length),D=re?b:null,H=L.useMemo(()=>p?nN(t,r,p):null,[t,r,p]),R=H?t.filter(ue=>H.nodeIds.has(ue.id)):t,z=H?r.filter(ue=>H.edgeIds.has(ue.id)):r,ne=L.useMemo(()=>eN(R,z,{detail:M,families:Y,focusId:D,neighborhoodOnly:!!D}),[R,z,M,Y,D]),oe=L.useMemo(()=>`${$}|${ne.nodes.map(ue=>ue.id).join("\0")}|${ne.edges.map(ue=>ue.id).join("\0")}`,[$,ne.nodes,ne.edges]),fe=b?t.find(ue=>ue.id===b)??null:null,{rfNodes:he,rfEdges:pe}=L.useMemo(()=>{const ue=HN(ne.nodes,ne.edges,b,{roles:c,testOverlay:h,layout:$});return W&&(ue.rfEdges=ue.rfEdges.map(je=>({...je,animated:!1}))),ue},[ne.nodes,ne.edges,b,W,c,h,$]);L.useEffect(()=>{if(!s)return;const ue=t.find(je=>je.file_path===s);ue&&E(ue.id)},[s,t]);const Z=L.useMemo(()=>tN(t,te),[t,te]),se=(ue,je)=>{E(je.id)},me=()=>{E(null),J(!1)},Ne=fe?d.jsx(BN,{node:fe,nodes:t,edges:r,onClose:me,onWhatIf:o,onSelect:E,onOpenFile:v,pinned:g===fe.id,onPin:_,onIsolate:y?ue=>{y(p===ue?null:ue)}:void 0}):null,we=ue=>{q(je=>{const Le=new Set(je);if(Le.has(ue)){if(Le.size===1)return je;Le.delete(ue)}else Le.add(ue);return Le})},ve=L.useMemo(()=>{const ue=new Set;for(const je of t)ue.add(bm(je.type));return ue},[t]),Pe=t.length-ne.nodes.length;return d.jsxs("div",{className:"impact-graph",style:{flex:1,minHeight:0,position:"relative",display:"flex",flexDirection:"column"},children:[d.jsxs("div",{className:"graph-toolbar","data-testid":"graph-toolbar",children:[d.jsxs("div",{className:"seg","aria-label":"Graph projection",children:[d.jsx("button",{type:"button","data-testid":"graph-view-2d",className:U==="2d"?"active":"","aria-pressed":U==="2d",onClick:()=>w("2d"),children:"2D map"}),d.jsx("button",{type:"button","data-testid":"graph-view-3d",className:U==="3d"?"active":"","aria-pressed":U==="3d",onClick:()=>w("3d"),children:"3D layers"})]}),d.jsxs("div",{className:"seg","aria-label":"Graph detail",children:[d.jsx("button",{type:"button","data-testid":"graph-detail-overview",className:M==="overview"?"active":"","aria-pressed":M==="overview",onClick:()=>A("overview"),children:"Overview"}),d.jsx("button",{type:"button","data-testid":"graph-detail-full",className:M==="full"?"active":"","aria-pressed":M==="full",onClick:()=>A("full"),children:"Full"})]}),d.jsx("div",{className:"seg","aria-label":"Graph families",children:["django","stitch","react"].filter(ue=>ve.has(ue)).map(ue=>d.jsx("button",{type:"button","data-testid":`graph-family-${ue}`,className:Y.has(ue)?"active":"","aria-pressed":Y.has(ue),onClick:()=>we(ue),children:ue},ue))}),U==="2d"?d.jsxs("label",{className:"graph-layout",children:["Layout",d.jsx("select",{id:"graph-layout","data-testid":"graph-layout",value:$,"aria-label":"2D layout algorithm",onChange:ue=>{var Le;const je=(Le=xc.find(nt=>nt.id===ue.target.value))==null?void 0:Le.id;je&&(F(je),oN(je))},children:xc.map(ue=>d.jsx("option",{value:ue.id,children:ue.label},ue.id))})]}):null,d.jsx("button",{type:"button",className:re?"chip-btn active":"chip-btn","data-testid":"graph-neighborhood",disabled:!b,onClick:()=>J(ue=>!ue),children:re?"Neighborhood":"Focus neighbors"}),p?d.jsx("button",{type:"button",className:"chip-btn active","data-testid":"graph-isolate-clear",onClick:()=>y==null?void 0:y(null),children:"Path isolate"}):null,d.jsxs("label",{className:"graph-search",children:[d.jsx("span",{className:"sr-only",children:"Search nodes"}),d.jsx("input",{"data-testid":"graph-search",placeholder:"Find a node",value:te,onChange:ue=>{Q(ue.target.value),V(!0)},onFocus:()=>V(!0),onBlur:()=>window.setTimeout(()=>V(!1),150)}),C&&te.trim()&&Z.length?d.jsx("ul",{className:"graph-search-hits","data-testid":"graph-search-hits",children:Z.map(ue=>d.jsx("li",{children:d.jsxs("button",{type:"button",onMouseDown:je=>je.preventDefault(),onClick:()=>{E(ue.id),Q(""),V(!1)},children:[ue.name,d.jsx("span",{className:"muted",children:li(ue.type)})]})},ue.id))}):null]}),d.jsxs("span",{className:"muted graph-count",children:[ne.nodes.length," nodes · ",ne.edges.length," edges",Pe?` · ${Pe} hidden`:""]})]}),d.jsx("div",{className:"graph-stage",children:t.length===0?d.jsxs("div",{className:"empty graph-walk-empty","data-testid":"graph-walk-empty",children:[d.jsx("h2",{children:"No typed nodes on this walk"}),d.jsx("p",{children:"This range did not hit models, views, routes, or React pages Loadpath extracts. Open the architecture map for the indexed graph."})]}):U==="3d"?d.jsxs("div",{className:"graph-3d","data-testid":"graph-3d",children:[d.jsx("p",{className:"graph-3d-hint",children:"Architecture layers are stacked in depth (Django → stitch → React). Drag to orbit, scroll to zoom, click a node to inspect it."}),d.jsx(L.Suspense,{fallback:d.jsx("p",{className:"muted graph-3d-hint",children:"Loading 3D layers…"}),children:d.jsx(RN,{nodes:ne.nodes,edges:ne.edges,selectedId:b,neighborIds:D?ne.neighborIds:IN,onSelect:ue=>{E(ue),ue||J(!1)}})}),Ne]}):d.jsxs(vm,{children:[d.jsxs(dk,{nodes:he,edges:pe,nodeTypes:$N,edgeTypes:ON,fitView:!1,minZoom:.25,nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,deleteKeyCode:null,onNodeClick:se,onPaneClick:me,proOptions:{hideAttribution:!1},"data-testid":"impact-graph",children:[d.jsx(FN,{topologyKey:oe}),d.jsx(mk,{}),d.jsx(zk,{pannable:!0,zoomable:!0,ariaLabel:"Impact graph overview",nodeColor:"var(--muted)",nodeStrokeColor:"transparent",nodeStrokeWidth:0,maskColor:"rgba(0, 0, 0, 0.45)",maskStrokeColor:"var(--accent)",maskStrokeWidth:1.4,bgColor:"var(--graph-bg)",style:{width:184,height:128}}),d.jsx(kk,{})]}),Ne]})})]})}function Em(){const t=localStorage.getItem("loadpath.editor")||"auto";return t==="cursor"||t==="vscode"||t==="system"?t:"auto"}function VN(t){localStorage.setItem("loadpath.editor",t)}async function WN(t,r,o,s=Em()){try{const a=await Te.openEditor(t,r,o??void 0,s);if(a.ok)return{ok:!0,message:`Opened ${r} in ${a.opened_with||"editor"}`};const u=a.urls||{},c=s==="vscode"?u.vscode:s==="cursor"?u.cursor:u.cursor||u.vscode;return c?(window.open(c,"_blank","noopener,noreferrer"),{ok:!0,message:`Opening ${r} via editor URL`}):{ok:!1,message:a.error||"Could not open editor"}}catch(a){return{ok:!1,message:a instanceof Error?a.message:String(a)}}}const Cp=[{value:"HEAD",label:"HEAD",group:"preset"},{value:"HEAD~1",label:"HEAD~1",group:"preset"}],UN=["preset","branch","tag","commit"];function GN(t){var a;if(!(t!=null&&t.git))return[...Cp];const r=((a=t.presets)!=null&&a.length?t.presets:Cp.map(u=>u.value)).map(u=>({value:u,label:u,group:"preset"})),o=new Set(r.map(u=>u.value)),s=[...r];for(const u of t.branches||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.current?`${u.name} (current)`:u.name,detail:u.subject,group:"branch"}));for(const u of t.tags||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.name,detail:u.subject,group:"tag"}));for(const u of t.commits||[])o.has(u.sha)||(o.add(u.sha),s.push({value:u.sha,label:u.short,detail:u.subject,group:"commit"}));return s}function YN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>s.value.toLowerCase().includes(o)||s.label.toLowerCase().includes(o)||(s.detail||"").toLowerCase().includes(o)):t}function XN(t){return UN.map(r=>({group:r,items:t.filter(o=>o.group===r)})).filter(r=>r.items.length>0)}function qN(t){return t==="preset"?"Common":t==="branch"?"Branches":t==="tag"?"Tags":"Recent commits"}function Mp({value:t,onChange:r,placeholder:o,testId:s,menuTestId:a,refs:u,onNeedRefs:c}){const h=L.useId(),p=L.useRef(null),[y,x]=L.useState(!1),[v,g]=L.useState(null),[_,S]=L.useState(0),N=L.useMemo(()=>{const j=GN(u);return v===null?j:YN(j,v)},[u,v]),b=L.useMemo(()=>XN(N),[N]);L.useEffect(()=>{y&&c()},[y,c]),L.useEffect(()=>{S(0)},[v,y]);const E=()=>{x(!1),g(null)},I=j=>{r(j.value),E()},w=j=>{if(j.key==="ArrowDown"){if(j.preventDefault(),!y){x(!0);return}S(A=>Math.min(A+1,Math.max(N.length-1,0)))}else if(j.key==="ArrowUp"){if(j.preventDefault(),!y)return;S(A=>Math.max(A-1,0))}else if(j.key==="Enter"&&y){j.preventDefault();const A=N[_];A&&I(A)}else j.key==="Escape"&&y&&(j.preventDefault(),E())};return d.jsxs("div",{className:"combo",ref:p,onBlur:j=>{j.currentTarget.contains(j.relatedTarget)||E()},children:[d.jsxs("div",{className:"combo-row",children:[d.jsx("input",{"data-testid":s,value:t,placeholder:o,spellCheck:!1,role:"combobox","aria-expanded":y,"aria-controls":h,"aria-autocomplete":"list",onChange:j=>{r(j.target.value),y&&g(j.target.value)},onKeyDown:w}),d.jsx("button",{type:"button",className:"icon-btn combo-toggle","data-testid":`${s}-toggle`,"aria-label":"Show recent refs","aria-expanded":y,onMouseDown:j=>j.preventDefault(),onClick:()=>y?E():x(!0),children:d.jsx(C0,{})})]}),y?d.jsx("div",{className:"combo-menu",id:h,role:"listbox","data-testid":a,children:b.length===0?d.jsx("div",{className:"combo-empty muted",children:"No matching refs — the typed value is kept"}):b.map(j=>d.jsxs("div",{className:"combo-group",children:[d.jsx("div",{className:"combo-heading",children:qN(j.group)}),j.items.map(A=>{const $=N.indexOf(A);return d.jsxs("button",{type:"button",role:"option","aria-selected":$===_,className:$===_?"combo-option active":"combo-option","data-testid":`ref-option-${A.group}`,onMouseDown:F=>F.preventDefault(),onMouseEnter:()=>S($),onClick:()=>I(A),children:[d.jsx("span",{className:"combo-label",children:A.label}),A.detail?d.jsx("span",{className:"combo-detail",children:A.detail}):null]},`${A.group}:${A.value}`)})]},j.group))}):null]})}function KN({initialPath:t,onSelect:r,onClose:o}){const[s,a]=L.useState(null),[u,c]=L.useState(t),[h,p]=L.useState(null),[y,x]=L.useState(""),[v,g]=L.useState(!1),_=L.useRef(null),S=L.useRef(0),N=async w=>{const j=S.current+1;S.current=j,g(!0);try{const A=await Te.browse(w);if(S.current!==j)return;a(A),c(A.path),p(A.is_git?A.path:null),x("")}catch(A){if(S.current!==j)return;x(A instanceof Error?A.message:String(A))}finally{S.current===j&&g(!1)}};L.useEffect(()=>{var w,j;N(t),(w=_.current)==null||w.focus(),(j=_.current)==null||j.select()},[t]);const b=h||(s==null?void 0:s.path)||u,E=h&&h!==(s==null?void 0:s.path)?h.split(/[\\/]/).filter(Boolean).pop():s!=null&&s.is_git?"this repository":"this folder",I=w=>{w.key==="Escape"&&(w.preventDefault(),o())};return d.jsx("div",{className:"modal-backdrop","data-testid":"repo-explorer","data-overlay":"true",onClick:o,onKeyDown:I,children:d.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"explorer-title",onClick:w=>w.stopPropagation(),children:[d.jsxs("div",{className:"modal-head",children:[d.jsxs("div",{children:[d.jsx("h2",{id:"explorer-title",children:"Select repository"}),d.jsx("p",{className:"muted",children:"Browse to a git root, or paste the full path."})]}),d.jsx("button",{type:"button",className:"btn ghost","data-testid":"explorer-cancel",onClick:o,children:"Cancel"})]}),d.jsxs("form",{className:"explorer-path",onSubmit:w=>{w.preventDefault(),N(u)},children:[d.jsx("input",{ref:_,"data-testid":"explorer-path",value:u,onChange:w=>c(w.target.value),spellCheck:!1,"aria-label":"Directory path"}),d.jsx("button",{type:"button",className:"btn",disabled:!(s!=null&&s.parent),onClick:()=>(s==null?void 0:s.parent)&&void N(s.parent),children:"Up"}),d.jsx("button",{type:"button",className:"btn",onClick:()=>s&&void N(s.home),children:"Home"}),d.jsx("button",{type:"submit",className:"btn",children:"Go"})]}),y?d.jsx("div",{className:"error",role:"alert",children:y}):null,d.jsx("div",{className:"explorer-list",role:"listbox","aria-label":"Folders","aria-busy":v,children:s!=null&&s.entries.length?s.entries.map(w=>{const j=h===w.path;return d.jsxs("button",{type:"button",role:"option","aria-selected":j,className:j?"explorer-row active":"explorer-row","data-testid":"explorer-entry","data-path":w.path,onClick:()=>p(w.path),onDoubleClick:()=>void N(w.path),children:[d.jsx(Tp,{}),d.jsx("span",{className:"explorer-name",children:w.name}),w.is_git?d.jsx("span",{className:"chip git-badge",children:"git"}):null]},w.path)}):d.jsx("div",{className:"muted explorer-empty",children:v?"Loading…":"No folders here"})}),d.jsxs("div",{className:"modal-foot",children:[d.jsx("span",{className:"muted explorer-current",title:b,children:b}),d.jsxs("button",{type:"button",className:"btn primary","data-testid":"explorer-use",disabled:!b,onClick:()=>b&&r(b),children:["Use ",E]})]})]})})}const QN={scan:{start:0,end:20},extract:{start:20,end:88},boot:{start:88,end:94},stitch:{start:94,end:99},skipped:{start:100,end:100},done:{start:100,end:100}},ZN=new Set(["scan","extract","boot","stitch"]);function JN(t){const r=t.phase||"";if(!r||r==="idle")return null;const o=QN[r];if(!o)return null;if(o.start===o.end)return o.end;const s=t.total||0;if(s<=0)return o.start;const a=Math.min(1,Math.max(0,(t.done||0)/s));return Math.round(o.start+(o.end-o.start)*a)}function ej(t){return!t.phase||t.phase==="idle"?null:typeof t.percent=="number"&&Number.isFinite(t.percent)?Math.max(0,Math.min(100,Math.round(t.percent))):JN(t)}const Qa=[{id:"obsidian",label:"Obsidian",group:"dark"},{id:"nord",label:"Nord",group:"dark"},{id:"solarized-dark",label:"Solarized Dark",group:"dark"},{id:"forest",label:"Forest",group:"dark"},{id:"rose",label:"Rose Pine",group:"dark"},{id:"amber",label:"Midnight Amber",group:"dark"},{id:"volcano",label:"Volcano",group:"dark"},{id:"lavender",label:"Lavender",group:"dark"},{id:"neon-noir",label:"Neon Noir",group:"dark"},{id:"synthwave",label:"Synthwave",group:"dark"},{id:"phosphor",label:"Phosphor",group:"dark"},{id:"aurora",label:"Aurora",group:"dark"},{id:"biolume",label:"Biolume",group:"dark"},{id:"carbon",label:"Carbon",group:"dark"},{id:"paper",label:"Paper",group:"light"},{id:"solarized-light",label:"Solarized Light",group:"light"},{id:"seafoam",label:"Seafoam",group:"light"},{id:"high-contrast",label:"High Contrast",group:"light"},{id:"sakura",label:"Sakura",group:"light"},{id:"citrus",label:"Citrus",group:"light"},{id:"peach",label:"Peach Fuzz",group:"light"},{id:"candy",label:"Cotton Candy",group:"light"},{id:"sky",label:"Clear Sky",group:"light"},{id:"coral",label:"Coral Reef",group:"light"}],tj="obsidian",Cm="loadpath.theme";function nj(t){return Qa.some(r=>r.id===t)}function Mm(){try{const t=localStorage.getItem(Cm)||"";if(nj(t))return t}catch{}return tj}function rj(t){var r;return((r=Qa.find(o=>o.id===t))==null?void 0:r.group)==="light"?"light":"dark"}function Pm(t){document.documentElement.dataset.theme=t,document.documentElement.style.colorScheme=rj(t);try{localStorage.setItem(Cm,t)}catch{}}const rc=[{id:"review",label:"Review",testId:"tab-review",shortcut:"1",icon:k0},{id:"architecture",label:"Architecture",testId:"tab-architecture",shortcut:"2",icon:N0},{id:"graph",label:"Impact graph",testId:"tab-graph",shortcut:"3",icon:j0},{id:"prs",label:"Pull requests",testId:"tab-prs",shortcut:"4",icon:b0},{id:"settings",label:"Settings",testId:"tab-settings",shortcut:"5",icon:E0}];function oc(t,r,o){let s;try{s=new URL(t)}catch{return}if(s.protocol!=="https:"||s.username||s.password)return;const a=s.hostname.toLowerCase();a!==r&&!a.endsWith(`.${r}`)||s.pathname.startsWith(o)&&window.open(s.toString(),"_blank","noopener,noreferrer")}function oj(){var gi,jo,mi,yi,vi,bo,Xr,an,ln,un;const[t,r]=L.useState("review"),[o,s]=L.useState(localStorage.getItem("loadpath.repo")||""),[a,u]=L.useState(localStorage.getItem("loadpath.base")||"HEAD~1"),[c,h]=L.useState(localStorage.getItem("loadpath.head")||"HEAD"),[p,y]=L.useState(null),[x,v]=L.useState(null),[g,_]=L.useState(null),[S,N]=L.useState([]),[b,E]=L.useState("review"),[I,w]=L.useState(""),[j,A]=L.useState(""),[$,F]=L.useState(null),[Y,q]=L.useState(!1),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState({}),[W,U]=L.useState([]),[M,D]=L.useState([]),[H,R]=L.useState(localStorage.getItem("loadpath.scmRepo")||""),[z,ne]=L.useState(localStorage.getItem("loadpath.provider")||"github"),[oe,fe]=L.useState(localStorage.getItem("loadpath.prNumber")||""),[he,pe]=L.useState(localStorage.getItem("loadpath.dirty")==="1"),[Z,se]=L.useState(0),[me,Ne]=L.useState(""),[we,ve]=L.useState(Mm),[Pe,ue]=L.useState(!1),[je,Le]=L.useState(!1),[nt,lt]=L.useState(!1),[ut,Ye]=L.useState(null),[wt,Yt]=L.useState(null),[gt,mt]=L.useState(localStorage.getItem("loadpath.testOverlay")==="1"),[Ct,ct]=L.useState(null),[et,On]=L.useState(localStorage.getItem("loadpath.watch")==="1"),[Mt,kn]=L.useState([]),[ui,Fn]=L.useState(null),[vo,lr]=L.useState(null),[Or,Hn]=L.useState(null),[Fr,ur]=L.useState(()=>{try{return!!(localStorage.getItem("loadpath.lastReviewId")&&(localStorage.getItem("loadpath.repo")||"").trim())}catch{return!1}}),[cr,Ft]=L.useState(null),[dt,Bn]=L.useState(null),[Vn,Nn]=L.useState(!1),[Wn,jn]=L.useState(!1),it=L.useRef(o);it.current=o;const dr=L.useRef(he);dr.current=he;const bn=L.useRef(!1);bn.current=je;const Pt=L.useRef(""),nn=L.useRef(""),xo=P=>{ve(P),Pm(P)},Ze=L.useRef(""),He=P=>{Ze.current=P,A(P)},En=P=>{let G=0,ce=!1;F(0);const Ce=()=>{Te.indexProgress(P).then(Re=>{if(!Ze.current)return;if(Re.phase&&Re.phase!=="idle"&&Re.message&&He(Re.message),ZN.has(Re.phase))ce=!0;else if(!ce)return;const mr=ej(Re);mr!=null&&(Re.phase==="scan"&&!Re.done?G=mr:G=Math.max(G,mr),F(G))}).catch(()=>{})};Ce();const Ie=window.setInterval(Ce,250);return()=>{window.clearInterval(Ie),F(null)}};L.useEffect(()=>{Te.settings().then(V).catch(()=>{}).finally(()=>ue(!0)),Te.repos().then(P=>N(P.repos)).catch(()=>{})},[]);const Un=()=>o.trim()?!0:(w("Point at a local repository path first."),!1);L.useEffect(()=>{if(t!=="architecture"||!o.trim())return;const P=o;let G=!1;return nn.current!==P&&Yn(P),Te.config(P).then(ce=>{!G&&it.current===P&&lr(ce)}).catch(()=>{}),Te.architectureHealth(P).then(ce=>{!G&&it.current===P&&Hn(ce)}).catch(()=>{}),()=>{G=!0}},[t,o]);const rn=P=>{it.current=P,s(P),localStorage.setItem("loadpath.repo",P),P.trim()!==Pt.current&&(Pt.current="",Ft(null))},Hr=L.useCallback(P=>{const G=(P??it.current).trim();return!G||Pt.current===G?Promise.resolve():(Pt.current=G,Te.gitRefs(G).then(ce=>{it.current.trim()===G&&Ft(ce)}).catch(()=>{Pt.current===G&&(Pt.current="",Ft(null))}))},[]),on=(P,G)=>{u(P),h(G),localStorage.setItem("loadpath.base",P),localStorage.setItem("loadpath.head",G)},It=(P,G,ce)=>{ne(P),R(G),localStorage.setItem("loadpath.provider",P),localStorage.setItem("loadpath.scmRepo",G),ce!==void 0&&(fe(ce),localStorage.setItem("loadpath.prNumber",ce))},Xt=P=>{y(P),se(0),Ye(wt&&P.nodes.some(G=>G.id===wt)?wt:null),ct(null),Fn(null),P.what_if||(v(P),P.id&&localStorage.setItem("loadpath.lastReviewId",P.id))},Gn=async P=>{try{const G=await Te.reviews(P);kn(G.reviews)}catch{kn([])}},wo=async P=>{try{Hn(await Te.architectureHealth(P))}catch{Hn(null)}},_o=P=>P==="github"?!!C.github_token_set:P==="gitlab"?!!C.gitlab_token_set:!!C.bitbucket_token_set,Rt=L.useCallback(async(P=z)=>{var G;try{const ce=await Te.scmRepos(P);D(ce.repos),(G=ce.user)!=null&&G.login&&V(Ce=>({...Ce,...P==="github"?{github_user:ce.user.login}:P==="gitlab"?{gitlab_user:ce.user.login}:{bitbucket_user:ce.user.login}}))}catch{D([])}},[z]);L.useEffect(()=>{if(t!=="prs")return;let P=!1;return Rt(z).catch(()=>{P||D([])}),()=>{P=!0}},[t,z,Rt]),L.useEffect(()=>{if(!dt)return;let P=!1,G=0;const ce=async()=>{try{const Ce=await Te.githubOAuthPoll(dt.flow_id);if(P)return;if(Ce.status==="complete"){Bn(null);const Ie=await Te.settings();V(Ie),Q(Ce.user?`Signed in to GitHub as ${Ce.user}`:"Signed in to GitHub"),Rt("github");return}if(Ce.status==="pending"||Ce.status==="slow_down"){G=window.setTimeout(ce,Math.max(Ce.interval||dt.interval,5)*1e3);return}Bn(null),w(Ce.status==="denied"?"GitHub sign-in was denied.":"GitHub sign-in expired. Try again.")}catch(Ce){if(P)return;Bn(null),w(Ce instanceof Error?Ce.message:String(Ce))}};return G=window.setTimeout(ce,Math.max(dt.interval,5)*1e3),()=>{P=!0,window.clearTimeout(G)}},[dt,Rt]),L.useEffect(()=>{if(!Vn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.bitbucket.connected){Nn(!1);const Re=await Te.settings();V(Re),Q(Ie.bitbucket.user?`Signed in to Bitbucket as ${Ie.bitbucket.user}`:"Signed in to Bitbucket"),Rt("bitbucket");return}if(Date.now()-ce>18e4){Nn(!1),w("Bitbucket sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;Nn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Vn,Rt]),L.useEffect(()=>{if(!Wn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.gitlab.connected){jn(!1);const Re=await Te.settings();V(Re),Q(Ie.gitlab.user?`Signed in to GitLab as ${Ie.gitlab.user}`:"Signed in to GitLab"),Rt("gitlab");return}if(Date.now()-ce>18e4){jn(!1),w("GitLab sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;jn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Wn,Rt]);const Yn=async(P=o,G=!1)=>{if(!P.trim())return null;nn.current=P,J(!0);try{const ce=await Te.architecture(P,!1);it.current===P&&_(ce);const Ce=Te.architectureGraph(P).then(Ie=>{it.current===P&&_(Re=>Re&&{...Re,nodes:Ie.nodes,edges:Ie.edges,graph_pending:!1})});return Ce.catch(()=>{_(Ie=>Ie&&it.current===P?{...Ie,graph_pending:!1}:Ie)}).finally(()=>{nn.current===P&&J(!1)}),G&&await Ce,ce}catch(ce){throw it.current===P&&J(!1),ce}},Br=async P=>{const G=P.trim();if(!(!G||G===it.current)){if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}w(""),Q(""),y(null),v(null),_(null),E("architecture"),rn(G),q(!0),He(`Loading ${S0(G)}…`);try{await Promise.all([Yn(G),Hr(G)])}catch(ce){it.current===G&&w(ce instanceof Error?ce.message:String(ce))}finally{it.current===G&&(He(""),q(!1))}}},Xn=async()=>{if(Ze.current||!Un())return;w(""),Q(""),He("Tracing load path…"),rn(o),on(a,c);const P=En(o);try{const G=await Te.review(o,a,c,!0,dr.current);Xt(G),E("review"),r("review"),await Te.repos().then(ce=>N(ce.repos)).catch(()=>{}),await Promise.all([Yn(o),Gn(o),wo(o)])}catch(G){w(G instanceof Error?G.message:String(G))}finally{P(),He("")}},fr=async(P=!0)=>{if(Ze.current||!Un())return;w(""),Q(""),He(P?"Indexing…":"Full reindex…"),rn(o);const G=En(o);try{await Te.index(o,P);const ce=await Yn(o);await Te.repos().then(Ce=>N(Ce.repos)).catch(()=>{}),ce!=null&&ce.indexed&&(E("architecture"),r("architecture"))}catch(ce){w(ce instanceof Error?ce.message:String(ce))}finally{G(),He("")}},Ve=async()=>{if(!Ze.current&&Un()){w(""),Q(""),He("Detecting layout…"),rn(o);try{const P=await Te.init(o);Q(P.message),await Te.repos().then(G=>N(G.repos)).catch(()=>{})}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},ci=async()=>{if(p!=null&&p.markdown)try{await navigator.clipboard.writeText(p.markdown),Q("Copied markdown brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Vr=async()=>{if(!Ze.current){if(p!=null&&p.what_if){w("What-if walks are hypothetical — they are not posted to a pull request. Restore the git-range walk first.");return}if(!(p!=null&&p.markdown)||!H||!oe){w("Pick a pull request first (Pull requests tab), then post the brief.");return}He("Posting Loadpath brief…");try{const P=await Te.postComment(z,H,Number(oe),p.markdown);Q(P.updated?"Updated the Loadpath PR comment":"Posted the Loadpath PR comment")}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},So=async()=>{if(!Ze.current){w(""),He("Fetching pull requests…");try{const P=await Te.prs(z,H,"open",o.trim()||void 0);U(P.pull_requests);const G=M.find(ce=>ce.slug.toLowerCase()===H.trim().toLowerCase());G!=null&&G.local_path&&rn(G.local_path)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},hr=async()=>{w("");try{const P=await Te.githubOAuthStart();Bn(P),oc(P.verification_uri_complete,"github.com","/login/device")}catch(P){w(P instanceof Error?P.message:String(P))}},di=async()=>{w("");try{const P=await Te.bitbucketOAuthStart();Nn(!0),oc(P.authorize_url,"bitbucket.org","/site/oauth2/authorize")}catch(P){Nn(!1),w(P instanceof Error?P.message:String(P))}},ko=async()=>{w("");try{const P=await Te.gitlabOAuthStart();jn(!0),oc(P.authorize_url,new URL(P.authorize_url).hostname,"/oauth/authorize")}catch(P){jn(!1),w(P instanceof Error?P.message:String(P))}},Cn=async P=>{if(!(Ze.current||!o.trim())){w(""),He("Walking what-if path…");try{const G=await Te.whatIf(o,P);Q(`${G.title} — ${G.confidence.level} · ${(G.sinks||[]).length} sinks`),Xt({...G,markdown:G.markdown||"",index:G.index||(p==null?void 0:p.index),workspace:G.workspace||(p==null?void 0:p.workspace)}),E("review"),r("review")}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},_t=()=>{if(x){Xt(x),E("review"),r("review"),Q("Restored the last git-range walk");return}y(null),se(0),Ye(null),ct(null),Fn(null),E("architecture"),r("architecture"),Q("")},fi=async P=>{var Ie;if(Ze.current)return;It(P.provider,P.repo,String(P.number));const G=M.find(Re=>Re.slug.toLowerCase()===P.repo.toLowerCase());G!=null&&G.local_path&&rn(G.local_path),w(""),He(`Fetching ${P.provider} #${P.number}…`);const ce=(G==null?void 0:G.local_path)||o,Ce=ce?En(ce):()=>{};try{const Re=await Te.reviewPr(P.provider,P.repo,P.number,(G==null?void 0:G.local_path)||o||void 0);Xt(Re),Re.pull_request&&typeof Re.pull_request.repo_path=="string"&&rn(Re.pull_request.repo_path),on(String(Re.base||P.target_branch),String(Re.head||P.source_branch)),E("review"),r("review"),typeof((Ie=Re.pull_request)==null?void 0:Ie.repo_path)=="string"&&Gn(Re.pull_request.repo_path)}catch(Re){on(P.base_sha||P.target_branch,P.head_sha||P.source_branch),r("review"),w(Re instanceof Error?Re.message:String(Re))}finally{Ce(),He("")}},yt=async P=>{w("");try{V(await Te.oauthDisconnect(P)),z===P&&D([]),Q(`Disconnected ${P}`)}catch(G){w(G instanceof Error?G.message:String(G))}},hi=async P=>{P.preventDefault();const G=new FormData(P.currentTarget),ce={github_token:String(G.get("github_token")||""),github_oauth_client_id:String(G.get("github_oauth_client_id")||""),github_host:String(G.get("github_host")||""),gitlab_token:String(G.get("gitlab_token")||""),gitlab_host:String(G.get("gitlab_host")||""),gitlab_oauth_client_id:String(G.get("gitlab_oauth_client_id")||""),gitlab_oauth_client_secret:String(G.get("gitlab_oauth_client_secret")||""),bitbucket_token:String(G.get("bitbucket_token")||""),bitbucket_username:String(G.get("bitbucket_username")||""),bitbucket_oauth_client_id:String(G.get("bitbucket_oauth_client_id")||""),bitbucket_oauth_client_secret:String(G.get("bitbucket_oauth_client_secret")||""),ai_provider:String(G.get("ai_provider")||"none"),ai_api_key:String(G.get("ai_api_key")||""),ai_model:String(G.get("ai_model")||""),ai_base_url:String(G.get("ai_base_url")||"")},Ce=S.length?{...ce,workspaces:S.map(Ie=>({path:Ie.path,name:Ie.name}))}:ce;try{V(await Te.saveSettings(Ce)),Q("Settings saved on this machine")}catch(Ie){w(Ie instanceof Error?Ie.message:String(Ie))}},pi=async()=>{if(!(!p||Ze.current)){He("Residual analysis…");try{const P=await Te.residual(p);Ne(P.note)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},Wr=L.useRef(Xn);Wr.current=Xn;const Mn=L.useRef(t);Mn.current=t;const qn=L.useRef(!1);qn.current=nt;const Pn=L.useRef(p);Pn.current=p;const qt=L.useRef(Z);qt.current=Z,L.useEffect(()=>{const P=localStorage.getItem("loadpath.lastReviewId"),G=(localStorage.getItem("loadpath.repo")||"").trim();if(!P||!G){ur(!1);return}let ce=!1;return Te.getReview(G,P).then(Ce=>{ce||(Xt(Ce),on(Ce.base||localStorage.getItem("loadpath.base")||"HEAD~1",Ce.head||localStorage.getItem("loadpath.head")||"HEAD"),Gn(G),wo(G))}).catch(()=>{}).finally(()=>{ce||ur(!1)}),()=>{ce=!0}},[]);const Ur=L.useRef("");L.useEffect(()=>{if(!et||!o.trim())return;let P=!1;const G=async()=>{try{const Ce=await Te.workspaceStatus(o);if(P)return;Ur.current&&Ce.fingerprint!==Ur.current&&!Ze.current&&(pe(!0),dr.current=!0,localStorage.setItem("loadpath.dirty","1"),Wr.current()),Ur.current=Ce.fingerprint}catch{}};G();const ce=window.setInterval(G,2e3);return()=>{P=!0,window.clearInterval(ce)}},[et,o]),L.useEffect(()=>{const P=G=>{var Ie;if((G.metaKey||G.ctrlKey)&&G.key.toLowerCase()==="k"){G.preventDefault(),lt(Re=>!Re);return}if(qn.current){G.key==="Escape"&&(G.preventDefault(),lt(!1));return}if(bn.current){G.key==="Escape"&&(G.preventDefault(),Le(!1));return}const ce=G.target;if(ce&&(ce.tagName==="INPUT"||ce.tagName==="TEXTAREA"||ce.tagName==="SELECT"||ce.isContentEditable)){G.key==="Escape"&&ce.blur();return}if(G.key==="Escape"){w(""),Q(""),Ye(wt),ct(null);return}if(G.key==="j"||G.key==="k"){const Re=((Ie=Pn.current)==null?void 0:Ie.read_order)||[];if(!Re.length)return;G.preventDefault();const xi=qt.current,mr=G.key==="j"?Math.min(Re.length-1,xi+1):Math.max(0,xi-1);se(mr);return}const Ce=rc.find(Re=>Re.shortcut===G.key);if(Ce&&!G.metaKey&&!G.ctrlKey&&!G.altKey&&r(Ce.id),(G.metaKey||G.ctrlKey)&&G.key==="Enter"){if(Mn.current==="settings"||Mn.current==="prs"||Ze.current)return;G.preventDefault(),Wr.current()}};return window.addEventListener("keydown",P),()=>window.removeEventListener("keydown",P)},[wt]);const Gr=async(P,G)=>{if(!o.trim())return;const ce=await WN(o,P,G);ce.ok?Q(ce.message):w(ce.message)},pr=async()=>{if(p)try{const P=await Te.exportHtml(p),G=URL.createObjectURL(P),ce=document.createElement("a");ce.href=G,ce.download=`loadpath-${(p.id||"review").slice(0,8)}.html`,ce.click(),URL.revokeObjectURL(G),Q("Saved HTML brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Yr=async P=>{if(o.trim()){He("Loading stored review…");try{const G=await Te.getReview(o,P);Xt(G),on(G.base||a,G.head||c),E("review"),r("review");const ce=Mt.findIndex(Ie=>Ie.id===P),Ce=ce>=0?Mt[ce+1]:void 0;if(Ce)try{Fn(await Te.reviewDiff(o,P,Ce.id))}catch{Fn(null)}}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},sn={selectedId:ut,onSelect:Ye,nodeRoles:p==null?void 0:p.node_roles,testOverlay:gt,isolateSource:Ct,onIsolate:ct,repoPath:o,onOpenFile:Gr,pinnedId:wt,onPin:Yt},Kn=[{id:"review",group:"Run",label:"Review this range",hint:"⌘/Ctrl+Enter",run:()=>void Xn()},...p!=null&&p.what_if?[{id:"exit-whatif",group:"Review",label:x?"Back to git-range walk":"Exit what-if walk",run:_t}]:[],{id:"index",group:"Run",label:"Index repository",run:()=>void fr(!0)},{id:"watch",group:"Run",label:et?"Stop watching working tree":"Watch working tree",run:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")}},{id:"tests",group:"Graph",label:gt?"Hide test overlay":"Show test overlay",run:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")}},{id:"export",group:"Review",label:"Export HTML brief",run:()=>void pr()},...rc.map(P=>({id:`tab-${P.id}`,group:"Tabs",label:`Go to ${P.label}`,hint:P.shortcut,run:()=>r(P.id)})),...((p==null?void 0:p.nodes)||[]).slice(0,30).map(P=>({id:`node-${P.id}`,group:"Nodes",label:P.name,hint:li(P.type),run:()=>{Ye(P.id),r("graph")}})),...Mt.slice(0,12).map(P=>({id:`hist-${P.id}`,group:"History",label:P.title||P.id,hint:`${P.level||""} ${P.created_at||""}`.trim(),run:()=>void Yr(P.id)}))],No=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.nodes)??[]:(p==null?void 0:p.nodes)??[],[b,g,p]),gr=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.edges)??[]:(p==null?void 0:p.edges)??[],[b,g,p]),Fe=p!=null&&p.index?`${p.index.counts.nodes} nodes · ${p.index.counts.edges} edges`:g!=null&&g.indexed?`${g.counts.nodes} nodes · ${g.counts.edges} edges`:"Not indexed",_s=((p==null?void 0:p.findings)||[]).filter(P=>!P.waived);return d.jsxs("div",{className:"app",children:[d.jsx("a",{className:"skip",href:"#main",children:"Skip to content"}),d.jsxs("nav",{className:"rail","data-testid":"rail","aria-label":"Primary",children:[d.jsxs("div",{className:"brand",children:[d.jsx("div",{className:"brand-mark",children:"Loadpath"}),d.jsx("div",{className:"brand-sub",children:"Load-path review"})]}),rc.map(P=>{const G=P.icon,ce=t===P.id;return d.jsxs("button",{type:"button","data-testid":P.testId,className:ce?"nav-item active":"nav-item","aria-current":ce?"page":void 0,"aria-label":P.label,onClick:()=>r(P.id),children:[d.jsx(G,{}),d.jsx("span",{children:P.label})]},P.id)}),d.jsxs("div",{className:"theme-pick",children:[d.jsx("label",{htmlFor:"theme-select",children:"Theme"}),d.jsx("select",{id:"theme-select","data-testid":"theme-select",value:we,onChange:P=>xo(P.target.value),children:["dark","light"].map(P=>d.jsx("optgroup",{label:P==="dark"?"Dark":"Light",children:Qa.filter(G=>G.group===P).map(G=>d.jsx("option",{value:G.id,children:G.label},G.id))},P))})]}),d.jsxs("div",{className:"rail-foot",children:[d.jsx("div",{className:"muted",role:"status",children:j||Fe}),d.jsxs("div",{className:"kbd-hint",children:[d.jsx("kbd",{children:"1"}),"–",d.jsx("kbd",{children:"5"})," tabs · ",d.jsx("kbd",{children:"⌘"}),d.jsx("kbd",{children:"K"})," palette · ",d.jsx("kbd",{children:"j"}),"/",d.jsx("kbd",{children:"k"})," read order"]})]})]}),d.jsxs("div",{className:"main",id:"main",children:[j?d.jsxs("div",{className:$!=null?"progress determinate":"progress",role:$!=null?"progressbar":"status","aria-label":j,"aria-live":"polite","aria-busy":"true","aria-valuemin":$!=null?0:void 0,"aria-valuemax":$!=null?100:void 0,"aria-valuenow":$??void 0,"data-testid":"progress",children:[d.jsx("i",{style:$!=null?{width:`${$}%`}:void 0}),d.jsx("span",{className:"sr-only",children:j})]}):null,d.jsxs("header",{className:"topbar","data-testid":"topbar",children:[S.length>0?d.jsxs("label",{className:"field workspace",children:[d.jsx("span",{children:"Workspace"}),d.jsxs("select",{"data-testid":"workspace-select",value:S.some(P=>P.path===o)?o:"",disabled:!!j,"aria-busy":Y,onChange:P=>{P.target.value&&Br(P.target.value)},children:[d.jsx("option",{value:"",children:"Indexed repos…"}),S.map(P=>d.jsxs("option",{value:P.path,children:[P.name,P.indexed?` (${P.counts.nodes})`:""]},P.path))]})]}):null,d.jsxs("label",{className:"field path",children:[d.jsx("span",{children:"Repository"}),d.jsxs("div",{className:"path-row",children:[d.jsx("input",{"data-testid":"repo-path",placeholder:"Local monorepo path",value:o,onChange:P=>{const G=P.target.value;s(G),G.trim()!==Pt.current&&(Pt.current="",Ft(null))},spellCheck:!1}),d.jsx("button",{type:"button",className:"icon-btn","data-testid":"btn-browse-repo","aria-label":"Browse for a local repository",onClick:()=>Le(!0),children:d.jsx(Tp,{})})]})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Base"}),d.jsx(Mp,{testId:"base-ref",menuTestId:"base-ref-menu",value:a,onChange:P=>on(P,c),placeholder:"base",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Head"}),d.jsx(Mp,{testId:"head-ref",menuTestId:"head-ref-menu",value:c,onChange:P=>on(a,P),placeholder:"head",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Working tree"}),d.jsx("button",{type:"button",className:he?"chip-btn active":"chip-btn","data-testid":"btn-dirty","aria-pressed":he,onClick:()=>{const P=!he;pe(P),localStorage.setItem("loadpath.dirty",P?"1":"0")},children:he?"Include uncommitted":"Committed range"})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Watch"}),d.jsx("button",{type:"button",className:et?"chip-btn active":"chip-btn","data-testid":"btn-watch","aria-pressed":et,onClick:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")},children:et?"Watching":"Paused"})]}),p?d.jsxs("div",{className:`merge-box compact ${p.confidence.level}`,"data-testid":"merge-box",children:[d.jsx("div",{className:`level ${p.confidence.level}`,children:p.confidence.level.toUpperCase()}),d.jsxs("div",{className:"muted",children:[p.what_if?"what-if · ":"",p.confidence.covered_sinks,"/",p.confidence.sinks," sinks"]})]}):null,d.jsxs("div",{className:"topbar-actions",children:[d.jsx("button",{type:"button","data-testid":"btn-init",disabled:!!j,onClick:Ve,children:"Draft config"}),d.jsx("button",{type:"button","data-testid":"btn-index",disabled:!!j,onClick:()=>fr(!0),children:"Index"}),d.jsx("button",{type:"button","data-testid":"btn-review",className:"btn primary",disabled:!!j,onClick:Xn,children:"Review"})]})]}),d.jsxs("div",{className:"alerts",children:[I?d.jsxs("div",{className:"error","data-testid":"error",role:"alert",children:[d.jsx("span",{children:I}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>w(""),"aria-label":"Dismiss error",children:"×"})]}):null,te?d.jsxs("div",{className:"banner","data-testid":"status-note",children:[d.jsx("span",{children:te}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>Q(""),"aria-label":"Dismiss",children:"×"})]}):null,((gi=p==null?void 0:p.index)!=null&&gi.stale||g!=null&&g.stale)&&(t==="review"||t==="architecture")?d.jsx("div",{className:"banner stale","data-testid":"index-stale",children:"Index is stale — files changed since the last extract. Index again before trusting this walk."}):null,((jo=p==null?void 0:p.index)==null?void 0:jo.django_boot)==="failed"||(g==null?void 0:g.django_boot)==="failed"?d.jsx("div",{className:"banner warn","data-testid":"django-boot-failed",children:((mi=p==null?void 0:p.index)==null?void 0:mi.django_boot_detail)||(g==null?void 0:g.django_boot_detail)||"django.setup() failed"}):null,(yi=p==null?void 0:p.workspace)!=null&&yi.dirty_overlaps_review&&t==="review"?d.jsxs("div",{className:"banner warn","data-testid":"dirty-tree",children:["Uncommitted files overlap this review: ",(p.workspace.dirty_overlap||[]).slice(0,6).join(", ")]}):null,p!=null&&p.what_if?d.jsxs("div",{className:"banner whatif","data-testid":"whatif-banner",children:[d.jsxs("span",{children:["Hypothetical walk from"," ",d.jsx("strong",{children:((vi=p.node)==null?void 0:vi.name)||"this node"}),". Loadpath ignored Base/Head and asked which sinks would feel this node change — not a filter of the current map."]}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-exit-whatif",onClick:_t,children:x?"Back to git range":"Back to architecture"})]}):null,Y?d.jsx("div",{className:"banner","data-testid":"workspace-loading",children:j||"Loading workspace…"}):null]}),d.jsxs("div",{className:"stage","aria-busy":Y||re,children:[t==="review"&&d.jsxs("div",{className:"content","data-testid":"review-layout",children:[d.jsx("aside",{className:"brief","data-testid":"brief",children:p?d.jsx(ij,{review:p,findings:_s,aiNote:me,busy:!!j,tourIndex:Z,onTour:se,onAskAi:pi,onCopy:ci,onPost:Vr,onSelect:Ye,onOpenFile:Gr,onExport:pr,history:Mt,diff:ui,onReopen:Yr,onWaiver:(P,G)=>{o.trim()&&Te.addWaiver(o,P,G||void 0,"from review").then(ce=>{lr(ce),Q(`Waived ${P} in loadpath.yml`)})}}):Fr?d.jsxs("div",{className:"empty","data-testid":"review-restoring",children:[d.jsx("h2",{children:"Restoring last review"}),d.jsx("p",{children:"Loading the walk this machine stored last time Loadpath was open."})]}):d.jsxs("div",{className:"empty","data-testid":"review-empty",children:[d.jsx("h2",{children:"Trace the force of this diff"}),d.jsx("p",{children:"The graph is the architecture. The brief is where this change travels — not a hunk list."}),d.jsxs("ol",{children:[d.jsx("li",{children:"Point at a Django + React monorepo, or pick an indexed workspace."}),d.jsxs("li",{children:["Index it. Missing ",d.jsx("code",{children:"loadpath.yml"})," is drafted from ",d.jsx("code",{children:"manage.py"})," and"," ",d.jsx("code",{children:"src/features"}),"."]}),d.jsx("li",{children:"Review a git range, or open a pull request so base/head become a three-dot merge-base."})]})]})}),d.jsx("div",{className:"graph-wrap","data-testid":"review-graph",children:p?d.jsx(nc,{nodes:p.nodes,edges:p.edges,onWhatIf:Cn,focusPath:(bo=p.read_order[Z])==null?void 0:bo.path,...sn}):null})]}),t==="architecture"&&d.jsxs("div",{className:"content","data-testid":"architecture-panel",children:[d.jsx("aside",{className:"brief","data-testid":"architecture-brief",children:g!=null&&g.indexed?d.jsx(sj,{architecture:g,busy:!!j,onReindex:()=>fr(!1),onReview:Xn,onSelect:Ye,config:vo,health:Or,onSaveConfig:P=>{Te.saveConfig(o,P).then(G=>{lr(G),Q("Wrote loadpath.yml")})},onWaiver:(P,G,ce)=>{Te.addWaiver(o,P,G,ce).then(Ce=>{lr(Ce),Q(`Waived ${P}`)})}}):Y?d.jsx("p",{className:"muted","data-testid":"architecture-loading",children:"Loading the index summary…"}):d.jsx("p",{className:"muted","data-testid":"architecture-empty",children:"Index this repo to build the architecture graph. Review then walks that same graph for a git range — it does not start from a hunk list."})}),d.jsx("div",{className:"graph-wrap","data-testid":"architecture-graph",children:(re||g!=null&&g.graph_pending)&&!((g==null?void 0:g.nodes)||[]).length?d.jsxs("div",{className:"empty graph-loading","data-testid":"graph-loading",children:[d.jsx("h2",{children:"Drawing the architecture map…"}),d.jsx("p",{children:(Xr=g==null?void 0:g.counts)!=null&&Xr.nodes?`${g.counts.nodes} indexed nodes. The brief is ready while the graph loads.`:"Fetching the indexed graph."})]}):g!=null&&g.indexed?d.jsx(nc,{nodes:g.nodes,edges:g.edges,onWhatIf:Cn,...sn,isolateSource:null,onIsolate:void 0}):null})]}),t==="graph"&&d.jsxs("div",{className:"graph-wrap","data-testid":"graph-full",style:{height:"100%"},children:[d.jsxs("div",{className:"graph-modes",children:[d.jsxs("div",{className:"seg","aria-label":"Graph scope",children:[d.jsx("button",{type:"button","aria-pressed":b==="review","data-testid":"graph-mode-review",className:b==="review"?"active":"",onClick:()=>E("review"),children:"This review"}),d.jsx("button",{type:"button","aria-pressed":b==="architecture","data-testid":"graph-mode-architecture",className:b==="architecture"?"active":"",onClick:()=>E("architecture"),children:"Indexed architecture"})]}),d.jsxs("div",{className:"legend","aria-hidden":"true",children:[d.jsxs("span",{children:[d.jsx("i",{})," cheap"]}),d.jsxs("span",{children:[d.jsx("i",{className:"exp"})," expensive"]}),d.jsxs("span",{children:[d.jsx("i",{className:"crit"})," critical"]}),d.jsxs("span",{children:[d.jsx("i",{className:"dash"})," inferred"]}),d.jsxs("span",{children:[d.jsx("i",{className:"seed"})," changed"]}),d.jsxs("span",{children:[d.jsx("i",{className:"down"})," downstream"]})]}),d.jsx("button",{type:"button",className:gt?"chip-btn active":"chip-btn","data-testid":"graph-test-overlay","aria-pressed":gt,onClick:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")},children:"Tests"})]}),No.length||p||g!=null&&g.indexed?d.jsx(nc,{nodes:No,edges:gr,onWhatIf:Cn,...sn,...b==="architecture"?{isolateSource:null,onIsolate:void 0,nodeRoles:void 0,testOverlay:!1}:{}}):re||g!=null&&g.graph_pending?d.jsx("p",{className:"empty","data-testid":"graph-loading",children:"Drawing the architecture map…"}):d.jsx("p",{className:"empty","data-testid":"graph-empty",children:"Index the repo or run a review first. Click a node to inspect it."})]}),t==="prs"&&d.jsxs("div",{className:"pr-list","data-testid":"pr-list",children:[d.jsxs("div",{className:"pr-toolbar",children:[d.jsxs("label",{className:"field provider",children:[d.jsx("span",{children:"Provider"}),d.jsxs("select",{"data-testid":"pr-provider",value:z,onChange:P=>It(P.target.value,H,oe),children:[d.jsx("option",{value:"github",children:"GitHub"}),d.jsx("option",{value:"gitlab",children:"GitLab"}),d.jsx("option",{value:"bitbucket",children:"Bitbucket"})]})]}),d.jsxs("label",{className:"field",children:[d.jsx("span",{children:"Repository"}),d.jsx("input",{"data-testid":"pr-repo",placeholder:M.length?"Search your repos":"owner/repo",value:H,onChange:P=>It(z,P.target.value,oe),list:"scm-repos",spellCheck:!1}),d.jsx("datalist",{id:"scm-repos",children:M.map(P=>d.jsxs("option",{value:P.slug,children:[P.private?"private":"public",P.local_path?" · local":""]},P.slug))})]}),d.jsx("button",{type:"button","data-testid":"btn-refresh-repos",className:"btn",disabled:!!j||!_o(z),onClick:()=>{Rt(z)},children:"My repos"}),d.jsx("button",{type:"button","data-testid":"btn-list-prs",className:"btn",disabled:!!j,onClick:So,children:"List PRs"})]}),M.length>0?d.jsxs("p",{className:"muted scm-count","data-testid":"scm-repo-count",children:[M.length," ",z," repositor",M.length===1?"y":"ies",z==="github"&&C.github_user?` · @${String(C.github_user)}`:"",z==="gitlab"&&C.gitlab_user?` · @${String(C.gitlab_user)}`:"",z==="bitbucket"&&C.bitbucket_user?` · ${String(C.bitbucket_user)}`:""]}):null,W.length===0?d.jsxs("div",{className:"empty","data-testid":"pr-empty",children:[d.jsx("h2",{children:"No pull requests loaded"}),d.jsx("p",{children:"Sign in under Settings (or paste a token), load your repositories, then list open PRs. Reviewing a PR fills base and head from its SHAs."})]}):W.map(P=>{var G;return d.jsxs("article",{className:"pr","data-testid":`pr-${P.number}`,children:[d.jsxs("h3",{children:["#",P.number," ",P.title]}),d.jsxs("div",{className:"pr-meta muted",children:[d.jsx("span",{className:`chip ${P.draft?"":"open"}`,children:P.draft?"draft":P.state}),d.jsx("span",{children:P.author}),d.jsxs("span",{children:[P.source_branch," → ",P.target_branch]}),P.loadpath?d.jsxs("span",{className:`chip ${P.loadpath.level||""}`,"data-testid":`pr-loadpath-${P.number}`,children:[((G=P.loadpath.level)==null?void 0:G.toUpperCase())||"REVIEWED",P.loadpath.contract_break&&P.loadpath.contract_break!=="none"?` · ${P.loadpath.contract_break}`:""]}):d.jsx("span",{className:"muted",children:"no Loadpath walk yet"})]}),d.jsxs("div",{className:"pr-actions",children:[d.jsxs("a",{href:P.url,target:"_blank",rel:"noreferrer",children:["Open on ",P.provider]}),d.jsx("button",{type:"button",className:"btn primary","data-testid":`pr-review-${P.number}`,onClick:()=>void fi(P),children:"Review this PR"})]})]},`${P.provider}-${P.number}`)})]}),t==="settings"&&Pe&&d.jsxs("form",{className:"settings","data-testid":"settings-form",onSubmit:hi,children:[d.jsxs("div",{children:[d.jsx("h1",{children:"Settings"}),d.jsx("p",{className:"muted",children:"Tokens stay on this machine in ~/.loadpath/settings.json. AI runs only on residual uncertainty the graph could not close."})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Appearance"}),d.jsx("p",{className:"muted",children:"Local to this browser. High contrast is a first-class theme, not an afterthought."}),d.jsx("div",{className:"theme-grid","data-testid":"theme-grid",children:Qa.map(P=>d.jsxs("button",{type:"button","data-theme":P.id,className:we===P.id?"theme-swatch active":"theme-swatch","data-testid":`theme-${P.id}`,onClick:()=>xo(P.id),children:[d.jsx("div",{className:"swatch-bar","aria-hidden":"true"}),d.jsx("div",{className:"name",children:P.label}),d.jsx("div",{className:"group",children:P.group})]},P.id))})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Editor"}),d.jsx("p",{className:"muted",children:"Open files from the inspector and read-order in Cursor, VS Code, or the system handler."}),d.jsx("label",{htmlFor:"editor-pref",children:"Preferred editor"}),d.jsxs("select",{id:"editor-pref","data-testid":"editor-pref",defaultValue:Em(),onChange:P=>VN(P.target.value),children:[d.jsx("option",{value:"auto",children:"Auto (Cursor, then VS Code)"}),d.jsx("option",{value:"cursor",children:"Cursor"}),d.jsx("option",{value:"vscode",children:"VS Code"}),d.jsx("option",{value:"system",children:"System default"})]})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Source control"}),d.jsx("p",{className:"muted",children:"Sign in with OAuth to list every repository the account can access. Tokens stay in ~/.loadpath/settings.json. A classic PAT still works if you prefer not to register an OAuth app."}),d.jsxs("div",{className:"scm-login","data-testid":"scm-github",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitHub"}),d.jsx("p",{className:"muted",children:C.github_token_set?C.github_user?`Signed in as @${String(C.github_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.github_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-github-disconnect",onClick:()=>void yt("github"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-github-login",disabled:!!dt||!C.github_oauth_ready,onClick:()=>void hr(),children:dt?"Waiting for GitHub…":"Sign in with GitHub"})})]}),dt?d.jsxs("p",{className:"oauth-code","data-testid":"github-user-code",children:["Enter ",d.jsx("code",{children:dt.user_code})," at GitHub if the browser did not fill it in."]}):null,C.github_oauth_ready?null:d.jsx("p",{className:"muted",children:"Sign-in needs a GitHub OAuth App with Device Flow enabled. Set LOADPATH_GITHUB_CLIENT_ID or paste the client ID below."}),d.jsx("label",{htmlFor:"github_oauth_client_id",children:"GitHub OAuth client ID"}),d.jsx("input",{id:"github_oauth_client_id",name:"github_oauth_client_id","data-testid":"github-oauth-client-id",placeholder:"Ov23…",defaultValue:String(C.github_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"github_token",children:"GitHub token (optional PAT)"}),d.jsx("input",{id:"github_token",name:"github_token",type:"password",placeholder:"ghp_…",autoComplete:"off"}),d.jsx("label",{htmlFor:"github_host",children:"GitHub host (Enterprise)"}),d.jsx("input",{id:"github_host",name:"github_host","data-testid":"github-host",placeholder:"github.com",defaultValue:String(C.github_host||""),autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-gitlab",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitLab"}),d.jsx("p",{className:"muted",children:C.gitlab_token_set?C.gitlab_user?`Signed in as @${String(C.gitlab_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.gitlab_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-gitlab-disconnect",onClick:()=>void yt("gitlab"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-gitlab-login",disabled:Wn||!C.gitlab_oauth_ready,onClick:()=>void ko(),children:Wn?"Waiting for GitLab…":"Sign in with GitLab"})})]}),d.jsx("label",{htmlFor:"gitlab_host",children:"GitLab host"}),d.jsx("input",{id:"gitlab_host",name:"gitlab_host","data-testid":"gitlab-host",placeholder:"gitlab.com",defaultValue:String(C.gitlab_host||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_id",children:"GitLab OAuth application ID"}),d.jsx("input",{id:"gitlab_oauth_client_id",name:"gitlab_oauth_client_id","data-testid":"gitlab-oauth-client-id",defaultValue:String(C.gitlab_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_secret",children:"GitLab OAuth secret"}),d.jsx("input",{id:"gitlab_oauth_client_secret",name:"gitlab_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_token",children:"GitLab token (optional PAT)"}),d.jsx("input",{id:"gitlab_token",name:"gitlab_token",type:"password",placeholder:"glpat-…",autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-bitbucket",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"Bitbucket"}),d.jsx("p",{className:"muted",children:C.bitbucket_token_set?C.bitbucket_user?`Signed in as ${String(C.bitbucket_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.bitbucket_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-bitbucket-disconnect",onClick:()=>void yt("bitbucket"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-bitbucket-login",disabled:Vn||!C.bitbucket_oauth_ready,onClick:()=>void di(),children:Vn?"Waiting for Bitbucket…":"Sign in with Bitbucket"})})]}),C.bitbucket_oauth_ready?null:d.jsxs("p",{className:"muted",children:["Sign-in needs a Bitbucket OAuth consumer (key + secret). Callback URL:"," ",d.jsx("code",{children:"/api/oauth/bitbucket/callback"})," on this app origin."]}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_id",children:"Bitbucket OAuth key"}),d.jsx("input",{id:"bitbucket_oauth_client_id",name:"bitbucket_oauth_client_id","data-testid":"bitbucket-oauth-client-id",defaultValue:String(C.bitbucket_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_secret",children:"Bitbucket OAuth secret"}),d.jsx("input",{id:"bitbucket_oauth_client_secret",name:"bitbucket_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_token",children:"Bitbucket token (optional app password)"}),d.jsx("input",{id:"bitbucket_token",name:"bitbucket_token",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_username",children:"Bitbucket username (app passwords)"}),d.jsx("input",{id:"bitbucket_username",name:"bitbucket_username",defaultValue:String(C.bitbucket_username||"")})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Residual AI"}),d.jsx("label",{htmlFor:"ai_provider",children:"Provider"}),d.jsxs("select",{id:"ai_provider",name:"ai_provider",defaultValue:String(((an=C.ai)==null?void 0:an.provider)||"none"),children:[d.jsx("option",{value:"none",children:"none (graph only)"}),d.jsx("option",{value:"anthropic",children:"Anthropic"}),d.jsx("option",{value:"openai",children:"OpenAI"}),d.jsx("option",{value:"grok",children:"Grok / xAI"}),d.jsx("option",{value:"deepseek",children:"DeepSeek"}),d.jsx("option",{value:"cursor",children:"Cursor-compatible (OpenAI protocol)"}),d.jsx("option",{value:"ollama",children:"Ollama local"})]}),d.jsx("label",{htmlFor:"ai_api_key",children:"API key"}),d.jsx("input",{id:"ai_api_key",name:"ai_api_key",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"ai_model",children:"Model"}),d.jsx("input",{id:"ai_model",name:"ai_model","data-testid":"ai-model",placeholder:"optional override",defaultValue:String(((ln=C.ai)==null?void 0:ln.model)||"")}),d.jsx("label",{htmlFor:"ai_base_url",children:"Base URL"}),d.jsx("input",{id:"ai_base_url",name:"ai_base_url","data-testid":"ai-base-url",placeholder:"optional, OpenAI-compatible",defaultValue:String(((un=C.ai)==null?void 0:un.base_url)||"")}),d.jsx("button",{className:"btn primary",type:"submit","data-testid":"btn-save-settings",children:"Save"})]})]})]})]}),d.jsx(x0,{open:nt,actions:Kn,onClose:()=>lt(!1)}),je?d.jsx(KN,{initialPath:o,onClose:()=>Le(!1),onSelect:P=>{if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}Le(!1),Br(P)}}):null]})}function ij({review:t,findings:r,aiNote:o,busy:s,tourIndex:a,onTour:u,onAskAi:c,onCopy:h,onPost:p,onSelect:y,onOpenFile:x,onExport:v,history:g,diff:_,onReopen:S,onWaiver:N}){var E,I,w,j,A,$,F,Y,q,re,J,te,Q,C,V,W,U;const b=[...new Set(t.confidence.reasons||[])];return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:`merge-box ${t.confidence.level}`,children:[d.jsxs("div",{className:`level ${t.confidence.level}`,children:[t.confidence.level.toUpperCase()," — ",t.title]}),b.length?d.jsx("ul",{className:"reasons",children:b.map(M=>d.jsx("li",{children:M},M))}):null,t.what_if?d.jsx("span",{className:"chip whatif","data-testid":"whatif-chip",children:"what-if"}):null,t.low_risk?d.jsx("span",{className:"chip",children:"low-risk"}):null,t.change_kinds.map(M=>d.jsx("span",{className:"chip",children:ns(M)},M)),(E=t.contract_break)!=null&&E.kind&&t.contract_break.kind!=="none"?d.jsxs("span",{className:`chip ${t.contract_break.kind==="breaking"?"blocker":""}`,"data-testid":"contract-kind",children:["contract ",t.contract_break.kind]}):null]}),d.jsxs("div",{className:"metrics",children:[d.jsxs("div",{className:"metric",children:[d.jsxs("div",{className:"n",children:[t.confidence.covered_sinks,"/",t.confidence.sinks]}),d.jsx("div",{className:"l",children:"Sinks tested"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:r.length}),d.jsx("div",{className:"l",children:"Findings"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:t.residuals.length}),d.jsx("div",{className:"l",children:"Residuals"})]})]}),d.jsx("pre",{className:"headline",children:t.headline}),(t.checklist||[]).length?d.jsxs("details",{className:"section",open:!0,"data-testid":"merge-checklist",children:[d.jsxs("summary",{children:["Merge checklist"," ",d.jsx("span",{className:"count",children:(t.checklist||[]).filter(M=>M.status==="todo").length})]}),(t.checklist||[]).map(M=>d.jsxs("div",{className:`check-item ${M.status}`,children:[d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.status}`,children:M.status}),M.title]}),M.detail?d.jsx("div",{className:"why",children:M.detail}):null,M.body?d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body||"")},children:"Copy test"}):null,M.kind==="finding"&&M.status==="todo"&&M.rule?d.jsx("button",{type:"button",className:"btn",onClick:()=>N(M.rule,M.node_id),children:"Waive in loadpath.yml"}):null]},M.id))]}):null,t.index?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Index ",d.jsx("span",{className:"count",children:t.index.counts.nodes})]}),d.jsxs("div",{className:"muted",children:["Walked ",t.index.counts.nodes," nodes / ",t.index.counts.edges," edges",t.index.reindex_skipped?" from an unchanged index":t.index.reindexed?" after an incremental refresh":" from the existing index",t.index.django_boot&&t.index.django_boot!=="off"?` · Django boot ${t.index.django_boot}`:"",(I=t.workspace)!=null&&I.three_dot?" · three-dot range":""]})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Read this ",d.jsx("span",{className:"count",children:t.read_order.length})]}),t.read_order.map((M,D)=>d.jsxs("div",{className:D===a?"read-item tour-current":"read-item",children:[d.jsxs("button",{type:"button",className:"linkish file",onClick:()=>u(D),children:[D+1,". ",M.path]}),d.jsx("div",{className:"why",children:M.why}),d.jsx("button",{type:"button",className:"btn",onClick:()=>x(M.path),children:"Open"})]},M.path)),t.read_order.length>0?d.jsxs("div",{className:"btn-row tour-row",children:[d.jsx("button",{type:"button",className:"btn","data-testid":"btn-tour-prev",disabled:a<=0,onClick:()=>u(Math.max(0,a-1)),children:"Previous"}),d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-tour-next",disabled:a>=t.read_order.length-1,onClick:()=>u(Math.min(t.read_order.length-1,a+1)),children:"Next in read order"}),d.jsxs("span",{className:"muted",children:[a+1,"/",t.read_order.length]})]}):null]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Clusters ",d.jsx("span",{className:"count",children:t.clusters.length})]}),t.clusters.map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:M.title})," — ",M.files.join(", ")]},M.id))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Architecture ",d.jsx("span",{className:"count",children:r.length})]}),r.length===0?d.jsx("div",{className:"muted",children:t.architecture_note}):r.map(M=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.severity}`,children:M.severity}),M.message]})},M.rule+M.message))]}),d.jsx(Im,{cards:t.deepening}),(j=(w=t.contract_break)==null?void 0:w.reasons)!=null&&j.length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Contract ",d.jsx("span",{className:"count",children:t.contract_break.kind})]}),t.contract_break.reasons.map(M=>d.jsx("div",{className:"muted",children:M},M)),($=(A=t.contract_break.sides)==null?void 0:A.rows)!=null&&$.length?d.jsxs("table",{className:"type-table","data-testid":"contract-sides",children:[d.jsx("thead",{children:d.jsxs("tr",{children:[d.jsx("th",{children:"Field"}),d.jsx("th",{children:"Serializer"}),d.jsx("th",{children:"Zod"}),d.jsx("th",{children:"GraphQL"})]})}),d.jsx("tbody",{children:t.contract_break.sides.rows.map(M=>d.jsxs("tr",{className:M.status,children:[d.jsx("td",{children:M.field}),d.jsx("td",{children:M.serializer?"yes":"—"}),d.jsx("td",{children:M.zod?"yes":"—"}),d.jsx("td",{children:M.graphql?"yes":"—"})]},M.field))})]}):null]}):null,(F=t.auth)!=null&&F.note?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Auth"}),d.jsx("div",{className:"muted",children:t.auth.note}),(t.auth.missing_permissions||[]).map(M=>d.jsxs("div",{className:"finding",children:[d.jsx("span",{className:"chip warning",children:"missing"}),M.name]},M.id))]}):null,(t.suggested_tests||[]).length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Suggested tests ",d.jsx("span",{className:"count",children:(Y=t.suggested_tests)==null?void 0:Y.length})]}),(t.suggested_tests||[]).map(M=>d.jsxs("div",{className:"residual",children:[d.jsx("strong",{children:M.title}),d.jsx("pre",{className:"headline",children:M.body}),d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body)},children:"Copy sketch"})]},M.title))]}):null,(q=t.trend)!=null&&q.note?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Confidence trend"}),d.jsx("div",{className:"muted",children:t.trend.note}),(t.trend.points||[]).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[M.level," · ",ic(M.created_at),M.sinks!=null?` · ${M.sinks} sinks`:""]},M.id))]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Residual ",d.jsx("span",{className:"count",children:t.residuals.length})]}),d.jsx("p",{className:"muted",children:"AI is only used here, on what the graph could not close."}),t.residuals.map(M=>d.jsx("div",{className:"residual muted",children:M},M))]}),g.length?d.jsxs("details",{className:"section","data-testid":"review-history",children:[d.jsxs("summary",{children:["History ",d.jsx("span",{className:"count",children:g.length})]}),_?d.jsx("div",{className:"muted",children:_.note}):null,g.slice(0,12).map(M=>d.jsxs("button",{type:"button",className:M.id===t.id?"history-item current":"history-item",onClick:()=>S(M.id),children:[d.jsx("span",{className:`chip ${M.level||""}`,children:M.level||"walk"}),M.title||M.id.slice(0,8),d.jsx("span",{className:"muted",children:M.created_at?ic(M.created_at):""})]},M.id))]}):null,(J=(re=t.evolution)==null?void 0:re.notes)!=null&&J.length||(Q=(te=t.evolution)==null?void 0:te.hotspots)!=null&&Q.some(M=>M.commits)?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Churn & coupling"}),(((C=t.evolution)==null?void 0:C.notes)||[]).map(M=>d.jsx("div",{className:"muted",children:M},M)),(((V=t.evolution)==null?void 0:V.hotspots)||[]).filter(M=>M.commits).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("span",{className:"file",children:M.path})," — ",M.commits," commits, bus factor ",M.bus_factor]},M.path))]}):null,d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:s,onClick:c,children:"Ask configured model"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-copy-markdown",onClick:h,children:"Copy markdown"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-export-html",onClick:v,children:"Save HTML"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-post-comment",disabled:s||!!t.what_if,title:t.what_if?"Hypothetical walks are not posted to a pull request":void 0,onClick:p,children:"Post to PR"})]}),o?d.jsx("pre",{className:"headline",children:o}):null,d.jsx("div",{className:"kicker",children:"Reviewers"}),d.jsx("div",{className:"muted",children:t.suggested_reviewers.join(", ")||"—"}),(W=t.codeowners_reviewers)!=null&&W.length?d.jsxs("div",{className:"muted",children:["CODEOWNERS: ",t.codeowners_reviewers.join(", ")]}):null,(U=t.knowledge_owners)!=null&&U.length?d.jsxs("div",{className:"muted",children:["Knowledge: ",t.knowledge_owners.join(", ")]}):null]})}function sj({architecture:t,busy:r,onReindex:o,onReview:s,onSelect:a,config:u,health:c,onSaveConfig:h,onWaiver:p}){var x;const y=t.findings.filter(v=>!v.waived);return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"merge-box high",children:[d.jsxs("div",{className:"level high",children:["INDEXED — ",t.counts.nodes," nodes"]}),d.jsxs("div",{className:"muted",style:{marginTop:8},children:[t.indexed_at?`Last index ${ic(t.indexed_at)}`:"Indexed",t.incremental?" · incremental":" · full",t.stale?" · stale":"",t.django_boot&&t.django_boot!=="off"?` · Django boot ${t.django_boot}`:""]}),d.jsxs("span",{className:"chip",children:[t.counts.edges," edges"]}),t.has_config?d.jsx("span",{className:"chip",children:"loadpath.yml"}):null]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Bounded contexts"}),Object.values(t.contexts).map(v=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v.name})," — ",(v.django_apps||[]).join(", ")||"no apps"," ·"," ",(v.owners||[]).join(", ")||"unowned"]},v.name))]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Rules ",d.jsx("span",{className:"count",children:(t.rules||[]).length})]}),(t.rules||[]).map(v=>d.jsx("div",{className:"muted",children:v},v))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Findings ",d.jsx("span",{className:"count",children:y.length})]}),y.length===0?d.jsx("div",{className:"muted",children:"No architecture rule hits on the full graph."}):y.map(v=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>v.node_id&&a(v.node_id),children:[d.jsx("span",{className:`chip ${v.severity}`,children:v.severity}),v.message]})},v.rule+v.message))]}),d.jsx(Im,{cards:t.deepening}),(x=c==null?void 0:c.points)!=null&&x.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"architecture-health",children:[d.jsxs("summary",{children:["Health over time ",d.jsx("span",{className:"count",children:c.points.length})]}),d.jsx("div",{className:"sparkline","aria-hidden":"true",children:c.points.map(v=>d.jsx("i",{className:v.level||"",title:`${v.level} · ${v.findings} findings`,style:{height:`${8+Math.min(24,(v.findings||0)*4)}px`}},v.id||v.created_at))}),Object.entries(c.contexts).map(([v,g])=>{var _;return d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v})," — last ",((_=g[g.length-1])==null?void 0:_.findings)??0," findings"]},v)})]}):null,u?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"loadpath.yml"}),d.jsx(w0,{config:u,busy:r,onSave:h,onWaiver:p})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Types"}),d.jsx("table",{className:"type-table",children:d.jsx("tbody",{children:Object.entries(t.type_counts||{}).sort((v,g)=>g[1]-v[1]).slice(0,12).map(([v,g])=>d.jsxs("tr",{children:[d.jsx("td",{children:li(v)}),d.jsx("td",{children:g})]},v))})})]}),d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:r,onClick:o,"data-testid":"btn-full-reindex",children:"Full reindex"}),d.jsx("button",{type:"button",className:"btn primary",disabled:r,onClick:s,children:"Review against this index"})]})]})}function Im({cards:t}){const r=t||[];return r.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"deepening-list",children:[d.jsxs("summary",{children:["Depth ",d.jsx("span",{className:"count",children:r.length})]}),d.jsx("p",{className:"muted",children:"Deepening opportunities: more behaviour behind a smaller interface, at a real seam."}),r.map(o=>d.jsxs("div",{className:"finding","data-testid":"deepening-card",children:[d.jsx("span",{className:`chip ${o.strength}`,children:_0(o.strength)}),o.top?d.jsx("span",{className:"chip",children:"top"}):null,d.jsx("strong",{children:o.title}),d.jsx("div",{className:"why",children:o.message}),o.deletion_test?d.jsxs("div",{className:"muted",children:["Deletion test: ",o.deletion_test]}):null,o.before&&o.after?d.jsxs("div",{className:"muted",children:[o.before," → ",o.after]}):null]},o.rule+o.title))]}):null}Pm(Mm());m0.createRoot(document.getElementById("root")).render(d.jsx(L.StrictMode,{children:d.jsx(oj,{})}));export{Kk as L,uj as a,aj as c,d as j,lj as l,L as r,li as t}; diff --git a/src/loadpath/static/assets/index-CdW5Vb1S.css b/src/loadpath/static/assets/index-eMEYJf2U.css similarity index 80% rename from src/loadpath/static/assets/index-CdW5Vb1S.css rename to src/loadpath/static/assets/index-eMEYJf2U.css index e233d8e..63e509a 100644 --- a/src/loadpath/static/assets/index-CdW5Vb1S.css +++ b/src/loadpath/static/assets/index-eMEYJf2U.css @@ -1 +1 @@ -.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}:root,[data-theme=obsidian]{--bg: #070b10;--bg-2: #0d141c;--surface: #121a24;--line: #1e2c3c;--ink: #e7eef6;--muted: #8b9bb0;--high: #2a9d8f;--medium: #e9c46a;--low: #e76f51;--critical: #e85d04;--accent: #4cc9f0;--rail-from: #0b1219;--rail-to: #070b10;--rail-active: #15202c;--btn: #173044;--btn-line: #24506c;--btn-primary: #134e4a;--btn-primary-line: #2a9d8f;--node-bg: #101822;--node-line: #2a3d52;--graph-bg: #070b10;--graph-grid: rgba(42, 80, 120, .09);--edge-cheap: #4a5568;--edge-expensive: #f4a261;--edge-critical: #e85d04;--shadow: rgba(76, 201, 240, .08)}[data-theme=nord]{--bg: #2e3440;--bg-2: #3b4252;--surface: #434c5e;--line: #4c566a;--ink: #eceff4;--muted: #d8dee9;--high: #a3be8c;--medium: #ebcb8b;--low: #bf616a;--critical: #d08770;--accent: #88c0d0;--rail-from: #3b4252;--rail-to: #2e3440;--rail-active: #4c566a;--btn: #434c5e;--btn-line: #81a1c1;--btn-primary: #5e81ac;--btn-primary-line: #88c0d0;--node-bg: #3b4252;--node-line: #81a1c1;--graph-bg: #2e3440;--graph-grid: rgba(136, 192, 208, .12);--edge-cheap: #4c566a;--edge-expensive: #d08770;--edge-critical: #bf616a;--shadow: rgba(136, 192, 208, .12)}[data-theme=solarized-dark]{--bg: #002b36;--bg-2: #073642;--surface: #0a3944;--line: #16444f;--ink: #eee8d5;--muted: #93a1a1;--high: #859900;--medium: #b58900;--low: #dc322f;--critical: #cb4b16;--accent: #2aa198;--rail-from: #073642;--rail-to: #002b36;--rail-active: #16444f;--btn: #073642;--btn-line: #268bd2;--btn-primary: #0a4a42;--btn-primary-line: #2aa198;--node-bg: #073642;--node-line: #268bd2;--graph-bg: #002b36;--graph-grid: rgba(42, 161, 152, .12);--edge-cheap: #586e75;--edge-expensive: #cb4b16;--edge-critical: #dc322f;--shadow: rgba(42, 161, 152, .12)}[data-theme=forest]{--bg: #0e1510;--bg-2: #152019;--surface: #1b2a20;--line: #2c4334;--ink: #e4f0e6;--muted: #8eaa96;--high: #6ab04c;--medium: #c8a951;--low: #e17055;--critical: #d35400;--accent: #7bed9f;--rail-from: #152019;--rail-to: #0e1510;--rail-active: #1f3326;--btn: #1f3326;--btn-line: #3d6b4f;--btn-primary: #1e4d32;--btn-primary-line: #6ab04c;--node-bg: #16241b;--node-line: #3d6b4f;--graph-bg: #0e1510;--graph-grid: rgba(123, 237, 159, .1);--edge-cheap: #3d6b4f;--edge-expensive: #c8a951;--edge-critical: #d35400;--shadow: rgba(123, 237, 159, .1)}[data-theme=rose]{--bg: #191724;--bg-2: #1f1d2e;--surface: #26233a;--line: #403d52;--ink: #e0def4;--muted: #908caa;--high: #9ccfd8;--medium: #f6c177;--low: #eb6f92;--critical: #eb6f92;--accent: #c4a7e7;--rail-from: #1f1d2e;--rail-to: #191724;--rail-active: #26233a;--btn: #26233a;--btn-line: #c4a7e7;--btn-primary: #3a2f4d;--btn-primary-line: #c4a7e7;--node-bg: #1f1d2e;--node-line: #524f67;--graph-bg: #191724;--graph-grid: rgba(196, 167, 231, .12);--edge-cheap: #524f67;--edge-expensive: #f6c177;--edge-critical: #eb6f92;--shadow: rgba(196, 167, 231, .12)}[data-theme=amber]{--bg: #120e0a;--bg-2: #1c1610;--surface: #261e16;--line: #3d2f22;--ink: #f4e6d0;--muted: #b59a78;--high: #c4d6a0;--medium: #e9b44c;--low: #d8572a;--critical: #c0392b;--accent: #f0a05a;--rail-from: #1c1610;--rail-to: #120e0a;--rail-active: #2b2218;--btn: #2b2218;--btn-line: #8a5a2b;--btn-primary: #4a3418;--btn-primary-line: #f0a05a;--node-bg: #1c1610;--node-line: #8a5a2b;--graph-bg: #120e0a;--graph-grid: rgba(240, 160, 90, .12);--edge-cheap: #5c4a38;--edge-expensive: #e9b44c;--edge-critical: #d8572a;--shadow: rgba(240, 160, 90, .12)}[data-theme=volcano]{--bg: #14090a;--bg-2: #1e0e10;--surface: #2a1416;--line: #4a2226;--ink: #fde8e4;--muted: #c48b86;--high: #7bed9f;--medium: #f6c90e;--low: #ff6b6b;--critical: #ff3b3b;--accent: #ff7b54;--rail-from: #1e0e10;--rail-to: #14090a;--rail-active: #32181b;--btn: #32181b;--btn-line: #ff7b54;--btn-primary: #5a1f18;--btn-primary-line: #ff7b54;--node-bg: #1e0e10;--node-line: #7a3330;--graph-bg: #14090a;--graph-grid: rgba(255, 123, 84, .12);--edge-cheap: #5a3330;--edge-expensive: #ff7b54;--edge-critical: #ff3b3b;--shadow: rgba(255, 123, 84, .14)}[data-theme=lavender]{--bg: #12101c;--bg-2: #1a1730;--surface: #221e3c;--line: #3b3560;--ink: #efeaff;--muted: #b3a7d6;--high: #80ffdb;--medium: #ffd166;--low: #ff6b9d;--critical: #ff4d6d;--accent: #c77dff;--rail-from: #1a1730;--rail-to: #12101c;--rail-active: #2a2550;--btn: #2a2550;--btn-line: #c77dff;--btn-primary: #3d2a66;--btn-primary-line: #c77dff;--node-bg: #1a1730;--node-line: #5a4d8a;--graph-bg: #12101c;--graph-grid: rgba(199, 125, 255, .12);--edge-cheap: #5a4d8a;--edge-expensive: #ffd166;--edge-critical: #ff4d6d;--shadow: rgba(199, 125, 255, .14)}[data-theme=neon-noir]{--bg: #05060a;--bg-2: #0a0c14;--surface: #10131c;--line: #1e2436;--ink: #f0f4ff;--muted: #8b93b0;--high: #39ff88;--medium: #ffe66d;--low: #ff2d95;--critical: #ff3d5a;--accent: #00f0ff;--rail-from: #0a0c14;--rail-to: #05060a;--rail-active: #151a2a;--btn: #151a2a;--btn-line: #00f0ff;--btn-primary: #063a40;--btn-primary-line: #00f0ff;--node-bg: #0a0c14;--node-line: #2a3550;--graph-bg: #05060a;--graph-grid: rgba(0, 240, 255, .12);--edge-cheap: #3a4560;--edge-expensive: #ff2d95;--edge-critical: #ff3d5a;--shadow: rgba(0, 240, 255, .22)}[data-theme=synthwave]{--bg: #1a0a2e;--bg-2: #240b3d;--surface: #2d1250;--line: #4a1d7a;--ink: #ffe6fb;--muted: #c49ad8;--high: #00f5d4;--medium: #ffd60a;--low: #ff6b9d;--critical: #ff006e;--accent: #ff2bd6;--rail-from: #240b3d;--rail-to: #1a0a2e;--rail-active: #3a1570;--btn: #3a1570;--btn-line: #ff2bd6;--btn-primary: #5a0a4a;--btn-primary-line: #ff2bd6;--node-bg: #240b3d;--node-line: #7b2cbf;--graph-bg: #1a0a2e;--graph-grid: rgba(255, 43, 214, .16);--edge-cheap: #5a3a80;--edge-expensive: #ff9e00;--edge-critical: #ff006e;--shadow: rgba(255, 43, 214, .24)}[data-theme=phosphor]{--bg: #020804;--bg-2: #061208;--surface: #0a1a0e;--line: #163c1e;--ink: #c8ffc8;--muted: #5aaa5a;--high: #39ff14;--medium: #c8f542;--low: #ffb000;--critical: #ff5e00;--accent: #00ff66;--rail-from: #061208;--rail-to: #020804;--rail-active: #0e2414;--btn: #0e2414;--btn-line: #00ff66;--btn-primary: #0a3a18;--btn-primary-line: #00ff66;--node-bg: #061208;--node-line: #1e6a32;--graph-bg: #020804;--graph-grid: rgba(0, 255, 102, .12);--edge-cheap: #1e5a2a;--edge-expensive: #c8f542;--edge-critical: #ff5e00;--shadow: rgba(0, 255, 102, .2)}[data-theme=aurora]{--bg: #071018;--bg-2: #0c1c28;--surface: #122636;--line: #1e3d52;--ink: #e8fff6;--muted: #7eb8a8;--high: #5fffcf;--medium: #ffe566;--low: #ff7eb6;--critical: #ff4d6d;--accent: #7cffb2;--rail-from: #0c1c28;--rail-to: #071018;--rail-active: #163044;--btn: #163044;--btn-line: #7cffb2;--btn-primary: #0e3d3a;--btn-primary-line: #7cffb2;--node-bg: #0c1c28;--node-line: #2a6a78;--graph-bg: #071018;--graph-grid: rgba(124, 255, 178, .12);--edge-cheap: #2a5a68;--edge-expensive: #c9a0ff;--edge-critical: #ff4d6d;--shadow: rgba(124, 255, 178, .18)}[data-theme=biolume]{--bg: #02141c;--bg-2: #042430;--surface: #073040;--line: #0a4a5c;--ink: #e6fffb;--muted: #6eb8b0;--high: #5dffb0;--medium: #ffe066;--low: #ff79c6;--critical: #ff4d6d;--accent: #18e7d4;--rail-from: #042430;--rail-to: #02141c;--rail-active: #0a3848;--btn: #0a3848;--btn-line: #18e7d4;--btn-primary: #0a4a48;--btn-primary-line: #18e7d4;--node-bg: #042430;--node-line: #1a7080;--graph-bg: #02141c;--graph-grid: rgba(24, 231, 212, .12);--edge-cheap: #1a5a68;--edge-expensive: #ff79c6;--edge-critical: #ff4d6d;--shadow: rgba(24, 231, 212, .2)}[data-theme=carbon]{--bg: #0d0d0f;--bg-2: #16161a;--surface: #1e1e24;--line: #33333c;--ink: #f2f2f4;--muted: #9a9aa8;--high: #3dd68c;--medium: #f0c040;--low: #ff5a5a;--critical: #ff2a2a;--accent: #ff2a2a;--rail-from: #16161a;--rail-to: #0d0d0f;--rail-active: #24242c;--btn: #24242c;--btn-line: #ff2a2a;--btn-primary: #4a1212;--btn-primary-line: #ff2a2a;--node-bg: #16161a;--node-line: #4a4a55;--graph-bg: #0d0d0f;--graph-grid: rgba(255, 42, 42, .1);--edge-cheap: #4a4a55;--edge-expensive: #ff8a3d;--edge-critical: #ff2a2a;--shadow: rgba(255, 42, 42, .18)}[data-theme=paper]{--bg: #f6f1e8;--bg-2: #efe6d6;--surface: #fffaf2;--line: #d9cbb6;--ink: #2b241c;--muted: #6f6456;--high: #2a7a4b;--medium: #b5811a;--low: #c0392b;--critical: #a93226;--accent: #1d6a7a;--rail-from: #efe6d6;--rail-to: #e7dcc8;--rail-active: #e2d3bb;--btn: #fffaf2;--btn-line: #c9b79a;--btn-primary: #d7eee0;--btn-primary-line: #2a7a4b;--node-bg: #fffaf2;--node-line: #c9b79a;--graph-bg: #f6f1e8;--graph-grid: rgba(29, 106, 122, .1);--edge-cheap: #b7a48c;--edge-expensive: #c0392b;--edge-critical: #a93226;--shadow: rgba(43, 36, 28, .08)}[data-theme=solarized-light]{--bg: #fdf6e3;--bg-2: #eee8d5;--surface: #f5efdc;--line: #d6cba9;--ink: #657b83;--muted: #93a1a1;--high: #859900;--medium: #b58900;--low: #dc322f;--critical: #cb4b16;--accent: #268bd2;--rail-from: #eee8d5;--rail-to: #e6dfc8;--rail-active: #e0d9c0;--btn: #fdf6e3;--btn-line: #93a1a1;--btn-primary: #e8efc8;--btn-primary-line: #859900;--node-bg: #fdf6e3;--node-line: #93a1a1;--graph-bg: #fdf6e3;--graph-grid: rgba(38, 139, 210, .12);--edge-cheap: #93a1a1;--edge-expensive: #cb4b16;--edge-critical: #dc322f;--shadow: rgba(101, 123, 131, .1)}[data-theme=seafoam]{--bg: #eef7f4;--bg-2: #dff0ea;--surface: #ffffff;--line: #b7d5cc;--ink: #17332c;--muted: #4d7268;--high: #1b8a5a;--medium: #c48a14;--low: #c44536;--critical: #9b2d22;--accent: #1d9a8a;--rail-from: #dff0ea;--rail-to: #cfe6de;--rail-active: #c4ddd4;--btn: #ffffff;--btn-line: #8fbfb2;--btn-primary: #d4f0e4;--btn-primary-line: #1b8a5a;--node-bg: #ffffff;--node-line: #8fbfb2;--graph-bg: #eef7f4;--graph-grid: rgba(29, 154, 138, .12);--edge-cheap: #8fbfb2;--edge-expensive: #c48a14;--edge-critical: #c44536;--shadow: rgba(23, 51, 44, .08)}[data-theme=high-contrast]{--bg: #ffffff;--bg-2: #f2f2f2;--surface: #ffffff;--line: #111111;--ink: #000000;--muted: #222222;--high: #007a33;--medium: #8a5a00;--low: #b00000;--critical: #9b0000;--accent: #0033cc;--rail-from: #f2f2f2;--rail-to: #e6e6e6;--rail-active: #d9d9d9;--btn: #ffffff;--btn-line: #000000;--btn-primary: #d9f2e3;--btn-primary-line: #007a33;--node-bg: #ffffff;--node-line: #000000;--graph-bg: #ffffff;--graph-grid: rgba(0, 0, 0, .12);--edge-cheap: #444444;--edge-expensive: #8a5a00;--edge-critical: #b00000;--shadow: rgba(0, 0, 0, .12)}[data-theme=sakura]{--bg: #fff0f5;--bg-2: #ffe4ee;--surface: #fff7fa;--line: #f5b8cc;--ink: #4a1830;--muted: #a05a78;--high: #1a8a5c;--medium: #c48a14;--low: #d63d6e;--critical: #b01040;--accent: #e84a8a;--rail-from: #ffe4ee;--rail-to: #f8d4e0;--rail-active: #f5c8d8;--btn: #fff7fa;--btn-line: #e89ab0;--btn-primary: #ffd6e6;--btn-primary-line: #e84a8a;--node-bg: #fff7fa;--node-line: #e89ab0;--graph-bg: #fff0f5;--graph-grid: rgba(232, 74, 138, .12);--edge-cheap: #d4a0b0;--edge-expensive: #d63d6e;--edge-critical: #b01040;--shadow: rgba(74, 24, 48, .1)}[data-theme=citrus]{--bg: #fffce8;--bg-2: #fff3b0;--surface: #fffef5;--line: #e8d44a;--ink: #2a2a08;--muted: #6a6a20;--high: #2a8a20;--medium: #d4a000;--low: #e85d04;--critical: #c0392b;--accent: #5aad14;--rail-from: #fff3b0;--rail-to: #ffe98a;--rail-active: #ffe066;--btn: #fffef5;--btn-line: #d4c030;--btn-primary: #e8f5b8;--btn-primary-line: #5aad14;--node-bg: #fffef5;--node-line: #d4c030;--graph-bg: #fffce8;--graph-grid: rgba(90, 173, 20, .14);--edge-cheap: #c4b040;--edge-expensive: #e85d04;--edge-critical: #c0392b;--shadow: rgba(42, 42, 8, .1)}[data-theme=peach]{--bg: #fff3eb;--bg-2: #ffe0cc;--surface: #fffaf6;--line: #f0c4a8;--ink: #3a2218;--muted: #8a5a48;--high: #2a8a5c;--medium: #d48a14;--low: #e85d3a;--critical: #c0392b;--accent: #ff6b35;--rail-from: #ffe0cc;--rail-to: #ffd4b8;--rail-active: #ffc8a8;--btn: #fffaf6;--btn-line: #e8a888;--btn-primary: #ffe0cc;--btn-primary-line: #ff6b35;--node-bg: #fffaf6;--node-line: #e8a888;--graph-bg: #fff3eb;--graph-grid: rgba(255, 107, 53, .12);--edge-cheap: #d4a088;--edge-expensive: #e85d3a;--edge-critical: #c0392b;--shadow: rgba(58, 34, 24, .1)}[data-theme=candy]{--bg: #f4f0ff;--bg-2: #e8dcff;--surface: #fbf8ff;--line: #d4c0f0;--ink: #2a1848;--muted: #6a5890;--high: #1a8a6a;--medium: #c48a14;--low: #e84a8a;--critical: #c01060;--accent: #ff5eb1;--rail-from: #e8dcff;--rail-to: #ddd0ff;--rail-active: #d4c4ff;--btn: #fbf8ff;--btn-line: #c4a8e8;--btn-primary: #ffd6ec;--btn-primary-line: #ff5eb1;--node-bg: #fbf8ff;--node-line: #c4a8e8;--graph-bg: #f4f0ff;--graph-grid: rgba(255, 94, 177, .14);--edge-cheap: #b0a0d0;--edge-expensive: #e84a8a;--edge-critical: #c01060;--shadow: rgba(42, 24, 72, .1)}[data-theme=sky]{--bg: #e8f4ff;--bg-2: #cfe8ff;--surface: #f5faff;--line: #90c8f0;--ink: #0a2848;--muted: #3a6080;--high: #0a8a4a;--medium: #c48a14;--low: #e85d3a;--critical: #c0392b;--accent: #0077ff;--rail-from: #cfe8ff;--rail-to: #b8dcff;--rail-active: #a8d4ff;--btn: #f5faff;--btn-line: #70b0e0;--btn-primary: #cfe8ff;--btn-primary-line: #0077ff;--node-bg: #f5faff;--node-line: #70b0e0;--graph-bg: #e8f4ff;--graph-grid: rgba(0, 119, 255, .12);--edge-cheap: #80b0d0;--edge-expensive: #e85d3a;--edge-critical: #c0392b;--shadow: rgba(10, 40, 72, .1)}[data-theme=coral]{--bg: #fff1ee;--bg-2: #ffddd6;--surface: #fff8f6;--line: #f0b0a4;--ink: #3a1814;--muted: #8a5048;--high: #0d9488;--medium: #d48a14;--low: #e85d4a;--critical: #c0392b;--accent: #0d9488;--rail-from: #ffddd6;--rail-to: #ffd0c6;--rail-active: #ffc4b8;--btn: #fff8f6;--btn-line: #e89888;--btn-primary: #d4f4ee;--btn-primary-line: #0d9488;--node-bg: #fff8f6;--node-line: #e89888;--graph-bg: #fff1ee;--graph-grid: rgba(13, 148, 136, .14);--edge-cheap: #d4a098;--edge-expensive: #e85d4a;--edge-critical: #c0392b;--shadow: rgba(58, 24, 20, .1)}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}:root{--radius: 6px;--radius-lg: 10px;--control-h: 32px;--font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;--mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;--focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);--space: 8px}body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:13px;line-height:1.45;-webkit-font-smoothing:antialiased}button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,a:focus-visible,summary:focus-visible{outline:none;box-shadow:var(--focus-ring)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.skip{position:absolute;left:12px;top:-40px;z-index:50;background:var(--surface);color:var(--ink);border:1px solid var(--accent);border-radius:var(--radius);padding:8px 12px}.skip:focus{top:12px}.app{display:grid;grid-template-columns:232px 1fr;height:100%}.rail{border-right:1px solid var(--line);background:linear-gradient(180deg,var(--rail-from),var(--rail-to));padding:16px 12px;display:flex;flex-direction:column;gap:2px;min-width:0}.brand{display:flex;flex-direction:column;gap:2px;padding:4px 8px 16px}.brand-mark{font-family:var(--mono);letter-spacing:.16em;font-size:11px;text-transform:uppercase;color:var(--accent);font-weight:600}.brand-sub{font-size:11px;color:var(--muted)}.nav-item{display:flex;align-items:center;gap:10px;background:transparent;border:0;text-align:left;padding:8px 10px;border-radius:var(--radius);color:var(--muted);cursor:pointer;width:100%}.nav-item:hover{background:color-mix(in srgb,var(--rail-active) 70%,transparent);color:var(--ink)}.nav-item.active{background:var(--rail-active);color:var(--ink);font-weight:500}.nav-item svg{flex-shrink:0}.theme-pick{margin-top:14px;display:grid;gap:4px;padding:0 2px}.theme-pick label{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);font-weight:500}.theme-pick select,.field select,.field input,.topbar input,.topbar select,.settings input,.settings select,.explorer-path input{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:0 10px;height:var(--control-h);width:100%}.rail-foot{margin-top:auto;padding:12px 8px 4px;border-top:1px solid var(--line);display:grid;gap:6px}.kbd-hint{font-size:11px;color:var(--muted)}kbd{font-family:var(--mono);font-size:10px;border:1px solid var(--line);border-radius:4px;padding:0 4px;background:var(--surface)}.main{display:flex;flex-direction:column;min-width:0;min-height:0;position:relative;background:var(--bg)}.progress{position:absolute;top:0;left:0;right:0;height:2px;overflow:hidden;z-index:30;background:color-mix(in srgb,var(--accent) 20%,transparent)}.progress i{display:block;height:100%;width:32%;background:var(--accent);animation:indeterminate 1.1s ease-in-out infinite}.progress.determinate i{width:0;animation:none;transform:none;transition:width .2s ease-out}@keyframes indeterminate{0%{transform:translate(-120%)}to{transform:translate(400%)}}.topbar{display:flex;gap:10px;align-items:flex-end;padding:10px 16px;border-bottom:1px solid var(--line);background:var(--bg-2);flex-wrap:wrap}.field{display:grid;gap:4px;min-width:0}.field>span{font-size:11px;color:var(--muted);font-weight:500}.field.path{flex:1;min-width:180px}.field.ref{width:188px;flex:0 0 188px}.field.workspace{width:180px;flex:0 0 180px}.path-row,.combo-row{display:flex;min-width:0}.path-row input,.combo-row input{flex:1;min-width:0}.combo{position:relative;min-width:0}.combo-row input{border-top-right-radius:0;border-bottom-right-radius:0}.topbar .icon-btn{width:var(--control-h);padding:0;flex:0 0 var(--control-h)}.combo-toggle{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0}.combo-menu{position:absolute;top:calc(100% + 4px);right:0;left:auto;min-width:340px;max-width:min(480px,70vw);max-height:360px;overflow:auto;z-index:40;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:0 12px 32px var(--shadow);padding:6px 0}.combo-heading{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600;padding:8px 12px 4px}.combo-menu .combo-option{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;background:transparent;border:0;border-radius:0;height:auto;padding:6px 12px;color:var(--ink);cursor:pointer}.combo-menu .combo-option:hover,.combo-menu .combo-option.active{background:var(--rail-active)}.combo-label{font-family:var(--mono);font-size:12px}.combo-detail{color:var(--muted);font-size:12px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.combo-empty{padding:10px 12px}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50;background:color-mix(in srgb,var(--bg) 72%,transparent);display:grid;place-items:center;padding:24px}.modal{width:min(720px,100%);max-height:min(640px,90vh);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 16px 48px var(--shadow);display:flex;flex-direction:column;overflow:hidden}.modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px 10px;border-bottom:1px solid var(--line)}.modal-head h2{font-size:15px}.modal-head .muted{margin:4px 0 0}.explorer-path{display:flex;gap:8px;padding:12px 16px;border-bottom:1px solid var(--line)}.explorer-path input{flex:1;min-width:0}.explorer-list{flex:1;overflow:auto;padding:8px;min-height:220px}.explorer-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:transparent;border:0;border-radius:var(--radius);padding:8px 10px;color:var(--ink);cursor:pointer;height:auto}.explorer-row:hover,.explorer-row.active{background:var(--rail-active)}.explorer-name{min-width:0;overflow:hidden;text-overflow:ellipsis}.git-badge{margin-left:auto;margin-bottom:0}.explorer-empty{padding:18px 10px}.modal-foot{display:flex;align-items:center;gap:12px;padding:12px 16px;border-top:1px solid var(--line)}.explorer-current{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mono);font-size:12px}.topbar input,.topbar select{min-width:0}.topbar-actions{display:flex;gap:8px;margin-left:auto;align-items:center;padding-bottom:0}.btn,.topbar button{background:var(--btn);border:1px solid var(--btn-line);border-radius:var(--radius);height:var(--control-h);padding:0 12px;cursor:pointer;font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;white-space:nowrap}.btn:hover,.topbar button:hover{filter:brightness(1.08)}.btn:disabled,.topbar button:disabled{opacity:.55;cursor:not-allowed;filter:none}.btn.primary{background:var(--btn-primary);border-color:var(--btn-primary-line)}.btn.ghost{background:transparent}.alerts{display:grid;gap:8px;padding:10px 16px 0}.alerts:empty{display:none;padding:0}.stage{flex:1;min-height:0;display:flex;flex-direction:column}.content{flex:1;min-height:0;display:grid;grid-template-columns:minmax(340px,420px) 1fr}.brief{overflow:auto;border-right:1px solid var(--line);padding:16px 18px 24px;background:radial-gradient(circle at 0 0,color-mix(in srgb,var(--accent) 8%,transparent),transparent 42%),var(--bg)}.graph-wrap{position:relative;min-height:0;display:flex;flex-direction:column}.impact-graph{flex:1;min-height:0;position:relative;display:flex;flex-direction:column}.graph-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:8px 14px;border-bottom:1px solid var(--line);background:var(--bg-2)}.graph-count{margin-left:auto;font-size:11px}.graph-layout{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--muted);letter-spacing:.04em}.graph-layout select{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:0 10px;height:26px;color:var(--ink);font:inherit;font-size:12px;letter-spacing:0;cursor:pointer}.chip-btn{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:4px 12px;color:var(--muted);cursor:pointer;height:26px}.chip-btn:hover{color:var(--ink)}.chip-btn.active{background:var(--rail-active);color:var(--ink)}.chip-btn:disabled{opacity:.45;cursor:not-allowed}.graph-stage{flex:1;min-height:0;position:relative;display:flex;flex-direction:column}.graph-stage .react-flow,.graph-3d,.graph-3d-host,.graph-3d-canvas-host{flex:1;width:100%;height:100%;min-height:280px}.graph-3d{position:relative;background:var(--graph-bg);display:flex;flex-direction:column}.graph-3d-host{position:relative;min-height:0;display:flex;flex-direction:column}.graph-3d-canvas-host{position:relative;min-height:0;background:var(--graph-bg)}.graph-3d canvas{display:block;width:100%;height:100%}.graph-3d-tip{position:absolute;pointer-events:none;z-index:2;max-width:320px;padding:6px 8px;border-radius:var(--radius);background:var(--surface);border:1px solid var(--line);color:var(--ink);font-size:11px;line-height:1.35;box-shadow:0 8px 24px var(--shadow)}.graph-3d-tip .t{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.graph-3d-tip .n{font-weight:600}.graph-3d-hint{position:absolute;left:10px;bottom:10px;z-index:2;margin:0;font-size:11px;color:var(--muted);max-width:min(420px,calc(100% - 24px));pointer-events:none}.graph-wrap .react-flow{background-color:var(--graph-bg);background-image:linear-gradient(var(--graph-grid) 1px,transparent 1px),linear-gradient(90deg,var(--graph-grid) 1px,transparent 1px);background-size:24px 24px}.react-flow__minimap{background:var(--graph-bg)!important;border:1px solid var(--line)!important;border-radius:var(--radius);overflow:hidden;box-shadow:0 8px 24px var(--shadow)}.react-flow__minimap-node{fill:var(--muted);stroke:none}.react-flow__minimap-node.selected{fill:var(--accent)}.react-flow__minimap-mask{fill:#00000073!important;stroke:var(--accent)!important}.react-flow__controls{box-shadow:none!important}.react-flow__controls-button{background:var(--surface)!important;border-bottom:1px solid var(--line)!important;fill:var(--ink)!important}h1{font-size:18px;margin:0 0 6px;font-weight:600}h2{font-size:13px;margin:0;font-weight:600}.merge-box{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-lg);padding:12px 14px;margin-bottom:12px}.merge-box.high{border-color:color-mix(in srgb,var(--high) 55%,var(--line))}.merge-box.medium{border-color:color-mix(in srgb,var(--medium) 55%,var(--line))}.merge-box.low{border-color:color-mix(in srgb,var(--low) 55%,var(--line))}.level{font-family:var(--mono);font-weight:600;font-size:14px}.level.high{color:var(--high)}.level.medium{color:var(--medium)}.level.low{color:var(--low)}.merge-title{margin-top:4px;font-size:13px;color:var(--ink)}.reasons{margin:10px 0 0;padding:0 0 0 18px;color:var(--muted)}.reasons li{margin:0 0 4px}.metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:0 0 14px}.metric{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);padding:8px 10px}.metric .n{font-family:var(--mono);font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}.metric .l{font-size:11px;color:var(--muted);margin-top:2px}.section{border-top:1px solid var(--line);padding:8px 0 4px}.section>summary{cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.07em;font-weight:600;padding:6px 0}.section>summary::-webkit-details-marker{display:none}.section>summary .count{font-family:var(--mono);letter-spacing:0;text-transform:none;border:1px solid var(--line);border-radius:999px;padding:0 7px;height:18px;display:inline-flex;align-items:center;font-size:11px}.kicker{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.08em;margin:16px 0 6px;font-weight:600}.chip{display:inline-flex;align-items:center;font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--line);margin:0 6px 6px 0;color:var(--muted);background:var(--surface)}.chip.blocker{color:var(--low);border-color:var(--low)}.chip.warning{color:var(--medium);border-color:var(--medium)}.chip.strong{color:var(--low);border-color:var(--low)}.chip.worth_exploring{color:var(--medium);border-color:var(--medium)}.chip.speculative{color:var(--muted);border-color:var(--line)}.chip.open{color:var(--high);border-color:color-mix(in srgb,var(--high) 50%,var(--line))}.file{font-family:var(--mono);font-size:12px;color:var(--accent)}.read-item,.finding,.residual{padding:8px 0;border-bottom:1px solid color-mix(in srgb,var(--line) 70%,transparent)}.read-item:last-child,.finding:last-child{border-bottom:0}.read-item.tour-current{background:color-mix(in srgb,var(--accent) 12%,var(--surface));border-color:var(--accent)}.tour-row{margin-top:8px;align-items:center}.field.dirty .chip-btn{height:32px}.muted{color:var(--muted);font-size:13px;line-height:1.45}.error{color:var(--low);padding:8px 12px;border:1px solid var(--low);background:color-mix(in srgb,var(--low) 10%,var(--surface));border-radius:var(--radius);display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.banner{padding:8px 12px;border-radius:var(--radius);border:1px solid var(--line);background:var(--surface);font-size:13px;line-height:1.45;display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.banner.warn{border-color:var(--medium);color:var(--medium)}.banner.stale{border-color:var(--low);color:var(--low)}.banner.whatif{border-color:var(--accent);align-items:center}.banner.whatif .btn{flex:0 0 auto;white-space:nowrap}.chip.whatif{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 55%,var(--line))}.whatif-hint{margin:10px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.banner .dismiss{background:transparent;border:0;color:inherit;cursor:pointer;height:auto;padding:0 2px;opacity:.7}.empty{padding:24px 8px;color:var(--muted);font-size:13px;line-height:1.55}.workspace-loading{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:220px;padding:48px 16px}.empty h2{font-size:16px;color:var(--ink);margin-bottom:8px}.empty ol{margin:12px 0 0 18px;padding:0}.empty code,code{font-family:var(--mono);font-size:12px;color:var(--accent)}.btn-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.pr-list{padding:16px;overflow:auto}.pr-toolbar{display:flex;gap:8px;align-items:flex-end;margin-bottom:14px}.pr-toolbar .field{flex:1}.pr-toolbar .field.provider{flex:0 0 140px}.scm-count{margin:0 0 12px;font-size:12px}.scm-login{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:10px 0;border-top:1px solid var(--line)}.scm-login:first-of-type{border-top:0;padding-top:0}.scm-login .btn-row{margin-top:0}.scm-login p{margin:2px 0 0}.oauth-code{font-size:13px;margin:0}.oauth-code code{font-size:14px;letter-spacing:.08em}.pr{border:1px solid var(--line);background:var(--surface);padding:12px 14px;border-radius:var(--radius-lg);margin-bottom:10px}.pr h3{margin:0 0 4px;font-size:14px;font-weight:600}.pr-meta{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;margin:6px 0 10px}.pr-actions{display:flex;gap:8px;align-items:center}.settings{padding:24px;max-width:760px;overflow:auto;display:grid;gap:16px}.settings-card{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-lg);padding:16px;display:grid;gap:8px}.settings-card h2{font-size:14px;margin-bottom:2px}.settings label{font-size:12px;color:var(--muted);font-weight:500}.theme-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}.theme-swatch{border:1px solid var(--line);background:var(--bg);color:var(--ink);border-radius:var(--radius);padding:10px;text-align:left;cursor:pointer;height:auto;box-shadow:0 1px 8px var(--shadow)}.theme-swatch.active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent),0 1px 8px var(--shadow)}.theme-swatch .swatch-bar{height:6px;border-radius:3px;margin-bottom:8px;background:linear-gradient(90deg,var(--accent),var(--high),var(--medium),var(--low))}.theme-swatch .name{font-size:13px;font-weight:600}.theme-swatch .group{font-size:11px;color:var(--muted)}.headline{white-space:pre-wrap;font-family:var(--mono);font-size:12px;color:var(--muted);margin:8px 0 0}.graph-modes{display:flex;gap:8px;align-items:center;padding:8px 14px;border-bottom:1px solid var(--line);background:var(--bg-2)}.seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;padding:2px;background:var(--surface)}.seg button,.graph-modes button{background:transparent;border:0;border-radius:999px;padding:4px 12px;color:var(--muted);cursor:pointer;height:26px}.seg button.active,.graph-modes button.active{background:var(--rail-active);color:var(--ink)}.legend{margin-left:auto;display:flex;gap:12px;color:var(--muted);font-size:11px}.legend i{display:inline-block;width:14px;height:2px;margin-right:6px;vertical-align:middle;background:var(--edge-cheap)}.legend i.exp{background:var(--edge-expensive)}.legend i.crit{background:var(--edge-critical);height:3px}.legend i.dash{border-top:2px dashed var(--muted);background:none;height:0}.legend i.seed{height:10px;width:10px;border-radius:2px;background:color-mix(in srgb,var(--medium) 70%,var(--node-bg))}.legend i.down{height:10px;width:10px;border-radius:2px;border:1px solid color-mix(in srgb,var(--accent) 45%,var(--node-line));background:var(--node-bg)}.inspector{position:absolute;top:12px;right:12px;z-index:5;width:300px;max-width:calc(100% - 24px);max-height:calc(100% - 24px);overflow-x:hidden;overflow-y:auto;overflow-wrap:break-word;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);padding:10px 12px;box-shadow:0 8px 24px var(--shadow);font-size:12px}.inspector .t{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.inspector .n,.inspector .file,.inspector .muted{overflow-wrap:break-word}.inspector .n{font-weight:600;margin:4px 0}.inspector-head{display:flex;align-items:flex-start;gap:8px}.inspector-roles{display:flex;flex-wrap:wrap;justify-content:flex-end;flex:1;gap:4px}.inspector-chip{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:1px 6px;border-radius:999px;border:1px solid var(--line);color:var(--muted);white-space:nowrap}.inspector-close{flex:0 0 auto;width:24px;height:24px;padding:0;border:1px solid var(--line);border-radius:var(--radius);background:transparent;color:var(--muted);font-size:16px;line-height:1;cursor:pointer}.inspector-close:hover{color:var(--ink)}.inspector-purpose{margin:6px 0 8px;color:var(--ink);font-size:12px;line-height:1.4}.inspector-layer{margin-top:4px;font-size:11px}.inspector-degree{font-size:11px}.inspector-path{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.inspector-facts{margin:10px 0 0;padding-top:8px;border-top:1px solid var(--line)}.inspector-fact{display:grid;grid-template-columns:minmax(64px,92px) minmax(0,1fr);gap:8px;padding:3px 0;align-items:start}.inspector-fact dt{color:var(--muted);font-size:11px;margin:0}.inspector-fact dd{margin:0;overflow-wrap:break-word}.inspector-section{margin-top:10px;padding-top:8px;border-top:1px solid var(--line)}.inspector-section h3{margin:0 0 6px;display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.07em;font-weight:600}.inspector-section .count{font-family:var(--mono);letter-spacing:0;text-transform:none;border:1px solid var(--line);border-radius:999px;padding:0 7px;height:18px;display:inline-flex;align-items:center;font-size:11px}.inspector-section ul{list-style:none;margin:0;padding:0}.inspector-section li{padding:4px 0;border-bottom:1px solid color-mix(in srgb,var(--line) 70%,transparent)}.inspector-section li:last-child{border-bottom:0}.inspector-link-name{display:block;font-weight:600;overflow-wrap:break-word}.inspector-link-meta{display:block;color:var(--muted);font-size:11px}.lp-node{padding:8px 10px;border-radius:var(--radius);border:1px solid var(--node-line);background:var(--node-bg);width:208px;max-width:100%;height:64px;box-sizing:border-box;box-shadow:0 0 0 1px var(--shadow);overflow:visible;position:relative}.lp-node .t{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.lp-node .n{font-size:13px;font-weight:600;line-height:1.2;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow-wrap:anywhere}.lp-node.selected{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}.lp-node.role-seed{border-color:var(--medium);background:color-mix(in srgb,var(--medium) 14%,var(--node-bg))}.lp-node.role-downstream{border-color:color-mix(in srgb,var(--accent) 45%,var(--node-line))}.lp-node.role-untested{box-shadow:inset 3px 0 0 var(--low)}.lp-node.role-tested{box-shadow:inset 3px 0 0 var(--high)}.lp-node.role-contract{outline:1px dashed color-mix(in srgb,var(--accent) 50%,transparent)}.lp-node.dim{opacity:.38}.merge-box.compact{padding:6px 10px;min-width:92px;margin:0}.merge-box.compact .level{font-size:12px}.palette-scrim{position:fixed;top:0;right:0;bottom:0;left:0;background:color-mix(in srgb,var(--bg) 55%,transparent);z-index:40;display:grid;place-items:start center;padding-top:12vh}.palette{width:min(640px,calc(100vw - 32px));background:var(--surface);border:1px solid var(--line);border-radius:12px;box-shadow:0 18px 60px var(--shadow);overflow:hidden}.palette input{width:100%;border:0;border-bottom:1px solid var(--line);background:transparent;color:var(--ink);padding:14px 16px;font:inherit}.palette ul{list-style:none;margin:0;padding:6px;max-height:360px;overflow:auto}.palette li button{width:100%;display:flex;justify-content:space-between;gap:12px;text-align:left;background:transparent;border:0;color:var(--ink);padding:8px 10px;border-radius:8px;cursor:pointer}.palette li button.active,.palette li button:hover{background:var(--rail-active)}.palette-foot{padding:8px 12px 10px}.graph-search{position:relative;min-width:140px}.graph-search input{width:100%;background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:6px 8px;font:inherit}.graph-search-hits{position:absolute;z-index:5;left:0;right:0;top:calc(100% + 4px);background:var(--surface);border:1px solid var(--line);border-radius:8px;list-style:none;margin:0;padding:4px;max-height:240px;overflow:auto}.graph-search-hits button{width:100%;display:flex;justify-content:space-between;gap:8px;background:transparent;border:0;color:var(--ink);text-align:left;padding:6px 8px;cursor:pointer}.graph-search-hits button:hover{background:var(--rail-active)}.inspector-link{display:flex;flex-direction:column;width:100%;background:transparent;border:0;color:inherit;text-align:left;cursor:pointer;padding:0}.file-row{display:flex;flex-direction:column;gap:6px}.linkish{background:none;border:0;color:inherit;font:inherit;text-align:left;cursor:pointer;padding:0}.history-item,.check-item{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;width:100%;background:transparent;border:0;color:inherit;font:inherit;text-align:left;padding:6px 0;cursor:pointer}.history-item.current{color:var(--accent)}.check-row{display:flex;gap:8px;align-items:center;margin:4px 0}.sparkline{display:flex;align-items:flex-end;gap:3px;height:36px;margin:8px 0}.sparkline i{flex:1;background:var(--muted);border-radius:2px 2px 0 0;min-width:4px}.sparkline i.high{background:var(--high)}.sparkline i.medium{background:var(--medium)}.sparkline i.low{background:var(--low)}.config-editor .field{display:flex;flex-direction:column;gap:4px;margin:8px 0}.config-editor input,.config-editor select{background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:6px 8px}.react-flow__node-load .react-flow__handle{width:8px;height:8px;border:none;background:transparent;opacity:0}.type-table{width:100%;border-collapse:collapse;font-size:12px}.type-table td{padding:3px 0}.type-table td:last-child{text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--muted)}@media(prefers-reduced-motion:reduce){.progress i{animation:none;width:100%}.progress.determinate i{width:var(--progress, 100%)}*{scroll-behavior:auto!important}}@media(max-width:960px){.app{grid-template-columns:56px 1fr}.brand-sub,.nav-item span,.theme-pick,.kbd-hint,.rail-foot .muted{display:none}.nav-item{justify-content:center;padding:10px}.content{grid-template-columns:1fr}.brief{border-right:0;border-bottom:1px solid var(--line);max-height:42vh}} +.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}:root,[data-theme=obsidian]{--bg: #070b10;--bg-2: #0d141c;--surface: #121a24;--line: #1e2c3c;--ink: #e7eef6;--muted: #8b9bb0;--high: #2a9d8f;--medium: #e9c46a;--low: #e76f51;--critical: #e85d04;--accent: #4cc9f0;--rail-from: #0b1219;--rail-to: #070b10;--rail-active: #15202c;--btn: #173044;--btn-line: #24506c;--btn-primary: #134e4a;--btn-primary-line: #2a9d8f;--node-bg: #101822;--node-line: #2a3d52;--graph-bg: #070b10;--graph-grid: rgba(42, 80, 120, .09);--edge-cheap: #4a5568;--edge-expensive: #f4a261;--edge-critical: #e85d04;--shadow: rgba(76, 201, 240, .08)}[data-theme=nord]{--bg: #2e3440;--bg-2: #3b4252;--surface: #434c5e;--line: #4c566a;--ink: #eceff4;--muted: #d8dee9;--high: #a3be8c;--medium: #ebcb8b;--low: #bf616a;--critical: #d08770;--accent: #88c0d0;--rail-from: #3b4252;--rail-to: #2e3440;--rail-active: #4c566a;--btn: #434c5e;--btn-line: #81a1c1;--btn-primary: #5e81ac;--btn-primary-line: #88c0d0;--node-bg: #3b4252;--node-line: #81a1c1;--graph-bg: #2e3440;--graph-grid: rgba(136, 192, 208, .12);--edge-cheap: #4c566a;--edge-expensive: #d08770;--edge-critical: #bf616a;--shadow: rgba(136, 192, 208, .12)}[data-theme=solarized-dark]{--bg: #002b36;--bg-2: #073642;--surface: #0a3944;--line: #16444f;--ink: #eee8d5;--muted: #93a1a1;--high: #859900;--medium: #b58900;--low: #dc322f;--critical: #cb4b16;--accent: #2aa198;--rail-from: #073642;--rail-to: #002b36;--rail-active: #16444f;--btn: #073642;--btn-line: #268bd2;--btn-primary: #0a4a42;--btn-primary-line: #2aa198;--node-bg: #073642;--node-line: #268bd2;--graph-bg: #002b36;--graph-grid: rgba(42, 161, 152, .12);--edge-cheap: #586e75;--edge-expensive: #cb4b16;--edge-critical: #dc322f;--shadow: rgba(42, 161, 152, .12)}[data-theme=forest]{--bg: #0e1510;--bg-2: #152019;--surface: #1b2a20;--line: #2c4334;--ink: #e4f0e6;--muted: #8eaa96;--high: #6ab04c;--medium: #c8a951;--low: #e17055;--critical: #d35400;--accent: #7bed9f;--rail-from: #152019;--rail-to: #0e1510;--rail-active: #1f3326;--btn: #1f3326;--btn-line: #3d6b4f;--btn-primary: #1e4d32;--btn-primary-line: #6ab04c;--node-bg: #16241b;--node-line: #3d6b4f;--graph-bg: #0e1510;--graph-grid: rgba(123, 237, 159, .1);--edge-cheap: #3d6b4f;--edge-expensive: #c8a951;--edge-critical: #d35400;--shadow: rgba(123, 237, 159, .1)}[data-theme=rose]{--bg: #191724;--bg-2: #1f1d2e;--surface: #26233a;--line: #403d52;--ink: #e0def4;--muted: #908caa;--high: #9ccfd8;--medium: #f6c177;--low: #eb6f92;--critical: #eb6f92;--accent: #c4a7e7;--rail-from: #1f1d2e;--rail-to: #191724;--rail-active: #26233a;--btn: #26233a;--btn-line: #c4a7e7;--btn-primary: #3a2f4d;--btn-primary-line: #c4a7e7;--node-bg: #1f1d2e;--node-line: #524f67;--graph-bg: #191724;--graph-grid: rgba(196, 167, 231, .12);--edge-cheap: #524f67;--edge-expensive: #f6c177;--edge-critical: #eb6f92;--shadow: rgba(196, 167, 231, .12)}[data-theme=amber]{--bg: #120e0a;--bg-2: #1c1610;--surface: #261e16;--line: #3d2f22;--ink: #f4e6d0;--muted: #b59a78;--high: #c4d6a0;--medium: #e9b44c;--low: #d8572a;--critical: #c0392b;--accent: #f0a05a;--rail-from: #1c1610;--rail-to: #120e0a;--rail-active: #2b2218;--btn: #2b2218;--btn-line: #8a5a2b;--btn-primary: #4a3418;--btn-primary-line: #f0a05a;--node-bg: #1c1610;--node-line: #8a5a2b;--graph-bg: #120e0a;--graph-grid: rgba(240, 160, 90, .12);--edge-cheap: #5c4a38;--edge-expensive: #e9b44c;--edge-critical: #d8572a;--shadow: rgba(240, 160, 90, .12)}[data-theme=volcano]{--bg: #14090a;--bg-2: #1e0e10;--surface: #2a1416;--line: #4a2226;--ink: #fde8e4;--muted: #c48b86;--high: #7bed9f;--medium: #f6c90e;--low: #ff6b6b;--critical: #ff3b3b;--accent: #ff7b54;--rail-from: #1e0e10;--rail-to: #14090a;--rail-active: #32181b;--btn: #32181b;--btn-line: #ff7b54;--btn-primary: #5a1f18;--btn-primary-line: #ff7b54;--node-bg: #1e0e10;--node-line: #7a3330;--graph-bg: #14090a;--graph-grid: rgba(255, 123, 84, .12);--edge-cheap: #5a3330;--edge-expensive: #ff7b54;--edge-critical: #ff3b3b;--shadow: rgba(255, 123, 84, .14)}[data-theme=lavender]{--bg: #12101c;--bg-2: #1a1730;--surface: #221e3c;--line: #3b3560;--ink: #efeaff;--muted: #b3a7d6;--high: #80ffdb;--medium: #ffd166;--low: #ff6b9d;--critical: #ff4d6d;--accent: #c77dff;--rail-from: #1a1730;--rail-to: #12101c;--rail-active: #2a2550;--btn: #2a2550;--btn-line: #c77dff;--btn-primary: #3d2a66;--btn-primary-line: #c77dff;--node-bg: #1a1730;--node-line: #5a4d8a;--graph-bg: #12101c;--graph-grid: rgba(199, 125, 255, .12);--edge-cheap: #5a4d8a;--edge-expensive: #ffd166;--edge-critical: #ff4d6d;--shadow: rgba(199, 125, 255, .14)}[data-theme=neon-noir]{--bg: #05060a;--bg-2: #0a0c14;--surface: #10131c;--line: #1e2436;--ink: #f0f4ff;--muted: #8b93b0;--high: #39ff88;--medium: #ffe66d;--low: #ff2d95;--critical: #ff3d5a;--accent: #00f0ff;--rail-from: #0a0c14;--rail-to: #05060a;--rail-active: #151a2a;--btn: #151a2a;--btn-line: #00f0ff;--btn-primary: #063a40;--btn-primary-line: #00f0ff;--node-bg: #0a0c14;--node-line: #2a3550;--graph-bg: #05060a;--graph-grid: rgba(0, 240, 255, .12);--edge-cheap: #3a4560;--edge-expensive: #ff2d95;--edge-critical: #ff3d5a;--shadow: rgba(0, 240, 255, .22)}[data-theme=synthwave]{--bg: #1a0a2e;--bg-2: #240b3d;--surface: #2d1250;--line: #4a1d7a;--ink: #ffe6fb;--muted: #c49ad8;--high: #00f5d4;--medium: #ffd60a;--low: #ff6b9d;--critical: #ff006e;--accent: #ff2bd6;--rail-from: #240b3d;--rail-to: #1a0a2e;--rail-active: #3a1570;--btn: #3a1570;--btn-line: #ff2bd6;--btn-primary: #5a0a4a;--btn-primary-line: #ff2bd6;--node-bg: #240b3d;--node-line: #7b2cbf;--graph-bg: #1a0a2e;--graph-grid: rgba(255, 43, 214, .16);--edge-cheap: #5a3a80;--edge-expensive: #ff9e00;--edge-critical: #ff006e;--shadow: rgba(255, 43, 214, .24)}[data-theme=phosphor]{--bg: #020804;--bg-2: #061208;--surface: #0a1a0e;--line: #163c1e;--ink: #c8ffc8;--muted: #5aaa5a;--high: #39ff14;--medium: #c8f542;--low: #ffb000;--critical: #ff5e00;--accent: #00ff66;--rail-from: #061208;--rail-to: #020804;--rail-active: #0e2414;--btn: #0e2414;--btn-line: #00ff66;--btn-primary: #0a3a18;--btn-primary-line: #00ff66;--node-bg: #061208;--node-line: #1e6a32;--graph-bg: #020804;--graph-grid: rgba(0, 255, 102, .12);--edge-cheap: #1e5a2a;--edge-expensive: #c8f542;--edge-critical: #ff5e00;--shadow: rgba(0, 255, 102, .2)}[data-theme=aurora]{--bg: #071018;--bg-2: #0c1c28;--surface: #122636;--line: #1e3d52;--ink: #e8fff6;--muted: #7eb8a8;--high: #5fffcf;--medium: #ffe566;--low: #ff7eb6;--critical: #ff4d6d;--accent: #7cffb2;--rail-from: #0c1c28;--rail-to: #071018;--rail-active: #163044;--btn: #163044;--btn-line: #7cffb2;--btn-primary: #0e3d3a;--btn-primary-line: #7cffb2;--node-bg: #0c1c28;--node-line: #2a6a78;--graph-bg: #071018;--graph-grid: rgba(124, 255, 178, .12);--edge-cheap: #2a5a68;--edge-expensive: #c9a0ff;--edge-critical: #ff4d6d;--shadow: rgba(124, 255, 178, .18)}[data-theme=biolume]{--bg: #02141c;--bg-2: #042430;--surface: #073040;--line: #0a4a5c;--ink: #e6fffb;--muted: #6eb8b0;--high: #5dffb0;--medium: #ffe066;--low: #ff79c6;--critical: #ff4d6d;--accent: #18e7d4;--rail-from: #042430;--rail-to: #02141c;--rail-active: #0a3848;--btn: #0a3848;--btn-line: #18e7d4;--btn-primary: #0a4a48;--btn-primary-line: #18e7d4;--node-bg: #042430;--node-line: #1a7080;--graph-bg: #02141c;--graph-grid: rgba(24, 231, 212, .12);--edge-cheap: #1a5a68;--edge-expensive: #ff79c6;--edge-critical: #ff4d6d;--shadow: rgba(24, 231, 212, .2)}[data-theme=carbon]{--bg: #0d0d0f;--bg-2: #16161a;--surface: #1e1e24;--line: #33333c;--ink: #f2f2f4;--muted: #9a9aa8;--high: #3dd68c;--medium: #f0c040;--low: #ff5a5a;--critical: #ff2a2a;--accent: #ff2a2a;--rail-from: #16161a;--rail-to: #0d0d0f;--rail-active: #24242c;--btn: #24242c;--btn-line: #ff2a2a;--btn-primary: #4a1212;--btn-primary-line: #ff2a2a;--node-bg: #16161a;--node-line: #4a4a55;--graph-bg: #0d0d0f;--graph-grid: rgba(255, 42, 42, .1);--edge-cheap: #4a4a55;--edge-expensive: #ff8a3d;--edge-critical: #ff2a2a;--shadow: rgba(255, 42, 42, .18)}[data-theme=paper]{--bg: #f6f1e8;--bg-2: #efe6d6;--surface: #fffaf2;--line: #d9cbb6;--ink: #2b241c;--muted: #6f6456;--high: #2a7a4b;--medium: #b5811a;--low: #c0392b;--critical: #a93226;--accent: #1d6a7a;--rail-from: #efe6d6;--rail-to: #e7dcc8;--rail-active: #e2d3bb;--btn: #fffaf2;--btn-line: #c9b79a;--btn-primary: #d7eee0;--btn-primary-line: #2a7a4b;--node-bg: #fffaf2;--node-line: #c9b79a;--graph-bg: #f6f1e8;--graph-grid: rgba(29, 106, 122, .1);--edge-cheap: #b7a48c;--edge-expensive: #c0392b;--edge-critical: #a93226;--shadow: rgba(43, 36, 28, .08)}[data-theme=solarized-light]{--bg: #fdf6e3;--bg-2: #eee8d5;--surface: #f5efdc;--line: #d6cba9;--ink: #657b83;--muted: #93a1a1;--high: #859900;--medium: #b58900;--low: #dc322f;--critical: #cb4b16;--accent: #268bd2;--rail-from: #eee8d5;--rail-to: #e6dfc8;--rail-active: #e0d9c0;--btn: #fdf6e3;--btn-line: #93a1a1;--btn-primary: #e8efc8;--btn-primary-line: #859900;--node-bg: #fdf6e3;--node-line: #93a1a1;--graph-bg: #fdf6e3;--graph-grid: rgba(38, 139, 210, .12);--edge-cheap: #93a1a1;--edge-expensive: #cb4b16;--edge-critical: #dc322f;--shadow: rgba(101, 123, 131, .1)}[data-theme=seafoam]{--bg: #eef7f4;--bg-2: #dff0ea;--surface: #ffffff;--line: #b7d5cc;--ink: #17332c;--muted: #4d7268;--high: #1b8a5a;--medium: #c48a14;--low: #c44536;--critical: #9b2d22;--accent: #1d9a8a;--rail-from: #dff0ea;--rail-to: #cfe6de;--rail-active: #c4ddd4;--btn: #ffffff;--btn-line: #8fbfb2;--btn-primary: #d4f0e4;--btn-primary-line: #1b8a5a;--node-bg: #ffffff;--node-line: #8fbfb2;--graph-bg: #eef7f4;--graph-grid: rgba(29, 154, 138, .12);--edge-cheap: #8fbfb2;--edge-expensive: #c48a14;--edge-critical: #c44536;--shadow: rgba(23, 51, 44, .08)}[data-theme=high-contrast]{--bg: #ffffff;--bg-2: #f2f2f2;--surface: #ffffff;--line: #111111;--ink: #000000;--muted: #222222;--high: #007a33;--medium: #8a5a00;--low: #b00000;--critical: #9b0000;--accent: #0033cc;--rail-from: #f2f2f2;--rail-to: #e6e6e6;--rail-active: #d9d9d9;--btn: #ffffff;--btn-line: #000000;--btn-primary: #d9f2e3;--btn-primary-line: #007a33;--node-bg: #ffffff;--node-line: #000000;--graph-bg: #ffffff;--graph-grid: rgba(0, 0, 0, .12);--edge-cheap: #444444;--edge-expensive: #8a5a00;--edge-critical: #b00000;--shadow: rgba(0, 0, 0, .12)}[data-theme=sakura]{--bg: #fff0f5;--bg-2: #ffe4ee;--surface: #fff7fa;--line: #f5b8cc;--ink: #4a1830;--muted: #a05a78;--high: #1a8a5c;--medium: #c48a14;--low: #d63d6e;--critical: #b01040;--accent: #e84a8a;--rail-from: #ffe4ee;--rail-to: #f8d4e0;--rail-active: #f5c8d8;--btn: #fff7fa;--btn-line: #e89ab0;--btn-primary: #ffd6e6;--btn-primary-line: #e84a8a;--node-bg: #fff7fa;--node-line: #e89ab0;--graph-bg: #fff0f5;--graph-grid: rgba(232, 74, 138, .12);--edge-cheap: #d4a0b0;--edge-expensive: #d63d6e;--edge-critical: #b01040;--shadow: rgba(74, 24, 48, .1)}[data-theme=citrus]{--bg: #fffce8;--bg-2: #fff3b0;--surface: #fffef5;--line: #e8d44a;--ink: #2a2a08;--muted: #6a6a20;--high: #2a8a20;--medium: #d4a000;--low: #e85d04;--critical: #c0392b;--accent: #5aad14;--rail-from: #fff3b0;--rail-to: #ffe98a;--rail-active: #ffe066;--btn: #fffef5;--btn-line: #d4c030;--btn-primary: #e8f5b8;--btn-primary-line: #5aad14;--node-bg: #fffef5;--node-line: #d4c030;--graph-bg: #fffce8;--graph-grid: rgba(90, 173, 20, .14);--edge-cheap: #c4b040;--edge-expensive: #e85d04;--edge-critical: #c0392b;--shadow: rgba(42, 42, 8, .1)}[data-theme=peach]{--bg: #fff3eb;--bg-2: #ffe0cc;--surface: #fffaf6;--line: #f0c4a8;--ink: #3a2218;--muted: #8a5a48;--high: #2a8a5c;--medium: #d48a14;--low: #e85d3a;--critical: #c0392b;--accent: #ff6b35;--rail-from: #ffe0cc;--rail-to: #ffd4b8;--rail-active: #ffc8a8;--btn: #fffaf6;--btn-line: #e8a888;--btn-primary: #ffe0cc;--btn-primary-line: #ff6b35;--node-bg: #fffaf6;--node-line: #e8a888;--graph-bg: #fff3eb;--graph-grid: rgba(255, 107, 53, .12);--edge-cheap: #d4a088;--edge-expensive: #e85d3a;--edge-critical: #c0392b;--shadow: rgba(58, 34, 24, .1)}[data-theme=candy]{--bg: #f4f0ff;--bg-2: #e8dcff;--surface: #fbf8ff;--line: #d4c0f0;--ink: #2a1848;--muted: #6a5890;--high: #1a8a6a;--medium: #c48a14;--low: #e84a8a;--critical: #c01060;--accent: #ff5eb1;--rail-from: #e8dcff;--rail-to: #ddd0ff;--rail-active: #d4c4ff;--btn: #fbf8ff;--btn-line: #c4a8e8;--btn-primary: #ffd6ec;--btn-primary-line: #ff5eb1;--node-bg: #fbf8ff;--node-line: #c4a8e8;--graph-bg: #f4f0ff;--graph-grid: rgba(255, 94, 177, .14);--edge-cheap: #b0a0d0;--edge-expensive: #e84a8a;--edge-critical: #c01060;--shadow: rgba(42, 24, 72, .1)}[data-theme=sky]{--bg: #e8f4ff;--bg-2: #cfe8ff;--surface: #f5faff;--line: #90c8f0;--ink: #0a2848;--muted: #3a6080;--high: #0a8a4a;--medium: #c48a14;--low: #e85d3a;--critical: #c0392b;--accent: #0077ff;--rail-from: #cfe8ff;--rail-to: #b8dcff;--rail-active: #a8d4ff;--btn: #f5faff;--btn-line: #70b0e0;--btn-primary: #cfe8ff;--btn-primary-line: #0077ff;--node-bg: #f5faff;--node-line: #70b0e0;--graph-bg: #e8f4ff;--graph-grid: rgba(0, 119, 255, .12);--edge-cheap: #80b0d0;--edge-expensive: #e85d3a;--edge-critical: #c0392b;--shadow: rgba(10, 40, 72, .1)}[data-theme=coral]{--bg: #fff1ee;--bg-2: #ffddd6;--surface: #fff8f6;--line: #f0b0a4;--ink: #3a1814;--muted: #8a5048;--high: #0d9488;--medium: #d48a14;--low: #e85d4a;--critical: #c0392b;--accent: #0d9488;--rail-from: #ffddd6;--rail-to: #ffd0c6;--rail-active: #ffc4b8;--btn: #fff8f6;--btn-line: #e89888;--btn-primary: #d4f4ee;--btn-primary-line: #0d9488;--node-bg: #fff8f6;--node-line: #e89888;--graph-bg: #fff1ee;--graph-grid: rgba(13, 148, 136, .14);--edge-cheap: #d4a098;--edge-expensive: #e85d4a;--edge-critical: #c0392b;--shadow: rgba(58, 24, 20, .1)}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}:root{--radius: 6px;--radius-lg: 10px;--control-h: 32px;--font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;--mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;--focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);--space: 8px}body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:13px;line-height:1.45;-webkit-font-smoothing:antialiased}button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,a:focus-visible,summary:focus-visible{outline:none;box-shadow:var(--focus-ring)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.skip{position:absolute;left:12px;top:-40px;z-index:50;background:var(--surface);color:var(--ink);border:1px solid var(--accent);border-radius:var(--radius);padding:8px 12px}.skip:focus{top:12px}.app{display:grid;grid-template-columns:232px 1fr;height:100%}.rail{border-right:1px solid var(--line);background:linear-gradient(180deg,var(--rail-from),var(--rail-to));padding:16px 12px;display:flex;flex-direction:column;gap:2px;min-width:0}.brand{display:flex;flex-direction:column;gap:2px;padding:4px 8px 16px}.brand-mark{font-family:var(--mono);letter-spacing:.16em;font-size:11px;text-transform:uppercase;color:var(--accent);font-weight:600}.brand-sub{font-size:11px;color:var(--muted)}.nav-item{display:flex;align-items:center;gap:10px;background:transparent;border:0;text-align:left;padding:8px 10px;border-radius:var(--radius);color:var(--muted);cursor:pointer;width:100%}.nav-item:hover{background:color-mix(in srgb,var(--rail-active) 70%,transparent);color:var(--ink)}.nav-item.active{background:var(--rail-active);color:var(--ink);font-weight:500}.nav-item svg{flex-shrink:0}.theme-pick{margin-top:14px;display:grid;gap:4px;padding:0 2px}.theme-pick label{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);font-weight:500}.theme-pick select,.field select,.field input,.topbar input,.topbar select,.settings input,.settings select,.explorer-path input{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:0 10px;height:var(--control-h);width:100%}.rail-foot{margin-top:auto;padding:12px 8px 4px;border-top:1px solid var(--line);display:grid;gap:6px}.kbd-hint{font-size:11px;color:var(--muted)}kbd{font-family:var(--mono);font-size:10px;border:1px solid var(--line);border-radius:4px;padding:0 4px;background:var(--surface)}.main{display:flex;flex-direction:column;min-width:0;min-height:0;position:relative;background:var(--bg)}.progress{position:absolute;top:0;left:0;right:0;height:2px;overflow:hidden;z-index:30;background:color-mix(in srgb,var(--accent) 20%,transparent)}.progress i{display:block;height:100%;width:32%;background:var(--accent);animation:indeterminate 1.1s ease-in-out infinite}.progress.determinate i{width:0;animation:none;transform:none;transition:width .2s ease-out}@keyframes indeterminate{0%{transform:translate(-120%)}to{transform:translate(400%)}}.topbar{display:flex;gap:10px;align-items:flex-end;padding:10px 16px;border-bottom:1px solid var(--line);background:var(--bg-2);flex-wrap:wrap}.field{display:grid;gap:4px;min-width:0}.field>span{font-size:11px;color:var(--muted);font-weight:500}.field.path{flex:1;min-width:180px}.field.ref{width:188px;flex:0 0 188px}.field.workspace{width:180px;flex:0 0 180px}.path-row,.combo-row{display:flex;min-width:0}.path-row input,.combo-row input{flex:1;min-width:0}.combo{position:relative;min-width:0}.combo-row input{border-top-right-radius:0;border-bottom-right-radius:0}.topbar .icon-btn{width:var(--control-h);padding:0;flex:0 0 var(--control-h)}.combo-toggle{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0}.combo-menu{position:absolute;top:calc(100% + 4px);right:0;left:auto;min-width:340px;max-width:min(480px,70vw);max-height:360px;overflow:auto;z-index:40;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:0 12px 32px var(--shadow);padding:6px 0}.combo-heading{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600;padding:8px 12px 4px}.combo-menu .combo-option{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;background:transparent;border:0;border-radius:0;height:auto;padding:6px 12px;color:var(--ink);cursor:pointer}.combo-menu .combo-option:hover,.combo-menu .combo-option.active{background:var(--rail-active)}.combo-label{font-family:var(--mono);font-size:12px}.combo-detail{color:var(--muted);font-size:12px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.combo-empty{padding:10px 12px}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50;background:color-mix(in srgb,var(--bg) 72%,transparent);display:grid;place-items:center;padding:24px}.modal{width:min(720px,100%);max-height:min(640px,90vh);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 16px 48px var(--shadow);display:flex;flex-direction:column;overflow:hidden}.modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 16px 10px;border-bottom:1px solid var(--line)}.modal-head h2{font-size:15px}.modal-head .muted{margin:4px 0 0}.explorer-path{display:flex;gap:8px;padding:12px 16px;border-bottom:1px solid var(--line)}.explorer-path input{flex:1;min-width:0}.explorer-list{flex:1;overflow:auto;padding:8px;min-height:220px}.explorer-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:transparent;border:0;border-radius:var(--radius);padding:8px 10px;color:var(--ink);cursor:pointer;height:auto}.explorer-row:hover,.explorer-row.active{background:var(--rail-active)}.explorer-name{min-width:0;overflow:hidden;text-overflow:ellipsis}.git-badge{margin-left:auto;margin-bottom:0}.explorer-empty{padding:18px 10px}.modal-foot{display:flex;align-items:center;gap:12px;padding:12px 16px;border-top:1px solid var(--line)}.explorer-current{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mono);font-size:12px}.topbar input,.topbar select{min-width:0}.topbar-actions{display:flex;gap:8px;margin-left:auto;align-items:center;padding-bottom:0}.btn,.topbar button{background:var(--btn);border:1px solid var(--btn-line);border-radius:var(--radius);height:var(--control-h);padding:0 12px;cursor:pointer;font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;white-space:nowrap}.btn:hover,.topbar button:hover{filter:brightness(1.08)}.btn:disabled,.topbar button:disabled{opacity:.55;cursor:not-allowed;filter:none}.btn.primary{background:var(--btn-primary);border-color:var(--btn-primary-line)}.btn.ghost{background:transparent}.alerts{display:grid;gap:8px;padding:10px 16px 0}.alerts:empty{display:none;padding:0}.stage{flex:1;min-height:0;display:flex;flex-direction:column}.content{flex:1;min-height:0;display:grid;grid-template-columns:minmax(340px,420px) 1fr}.brief{overflow:auto;border-right:1px solid var(--line);padding:16px 18px 24px;background:radial-gradient(circle at 0 0,color-mix(in srgb,var(--accent) 8%,transparent),transparent 42%),var(--bg)}.graph-wrap{position:relative;min-height:0;display:flex;flex-direction:column}.impact-graph{flex:1;min-height:0;position:relative;display:flex;flex-direction:column}.graph-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:8px 14px;border-bottom:1px solid var(--line);background:var(--bg-2)}.graph-count{margin-left:auto;font-size:11px}.graph-layout{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--muted);letter-spacing:.04em}.graph-layout select{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:0 10px;height:26px;color:var(--ink);font:inherit;font-size:12px;letter-spacing:0;cursor:pointer}.chip-btn{background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:4px 12px;color:var(--muted);cursor:pointer;height:26px}.chip-btn:hover{color:var(--ink)}.chip-btn.active{background:var(--rail-active);color:var(--ink)}.chip-btn:disabled{opacity:.45;cursor:not-allowed}.graph-stage{flex:1;min-height:0;position:relative;display:flex;flex-direction:column}.graph-stage .react-flow,.graph-3d,.graph-3d-host,.graph-3d-canvas-host{flex:1;width:100%;height:100%;min-height:280px}.graph-3d{position:relative;background:var(--graph-bg);display:flex;flex-direction:column}.graph-3d-host{position:relative;min-height:0;display:flex;flex-direction:column}.graph-3d-canvas-host{position:relative;min-height:0;background:var(--graph-bg)}.graph-3d canvas{display:block;width:100%;height:100%}.graph-3d-tip{position:absolute;pointer-events:none;z-index:2;max-width:320px;padding:6px 8px;border-radius:var(--radius);background:var(--surface);border:1px solid var(--line);color:var(--ink);font-size:11px;line-height:1.35;box-shadow:0 8px 24px var(--shadow)}.graph-3d-tip .t{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.graph-3d-tip .n{font-weight:600}.graph-3d-hint{position:absolute;left:10px;bottom:10px;z-index:2;margin:0;font-size:11px;color:var(--muted);max-width:min(420px,calc(100% - 24px));pointer-events:none}.graph-wrap .react-flow{background-color:var(--graph-bg);background-image:linear-gradient(var(--graph-grid) 1px,transparent 1px),linear-gradient(90deg,var(--graph-grid) 1px,transparent 1px);background-size:24px 24px}.react-flow__minimap{background:var(--graph-bg)!important;border:1px solid var(--line)!important;border-radius:var(--radius);overflow:hidden;box-shadow:0 8px 24px var(--shadow)}.react-flow__minimap-node{fill:var(--muted);stroke:none}.react-flow__minimap-node.selected{fill:var(--accent)}.react-flow__minimap-mask{fill:#00000073!important;stroke:var(--accent)!important}.react-flow__controls{box-shadow:none!important}.react-flow__controls-button{background:var(--surface)!important;border-bottom:1px solid var(--line)!important;fill:var(--ink)!important}h1{font-size:18px;margin:0 0 6px;font-weight:600}h2{font-size:13px;margin:0;font-weight:600}.merge-box{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-lg);padding:12px 14px;margin-bottom:12px}.merge-box.high{border-color:color-mix(in srgb,var(--high) 55%,var(--line))}.merge-box.medium{border-color:color-mix(in srgb,var(--medium) 55%,var(--line))}.merge-box.low{border-color:color-mix(in srgb,var(--low) 55%,var(--line))}.level{font-family:var(--mono);font-weight:600;font-size:14px}.level.high{color:var(--high)}.level.medium{color:var(--medium)}.level.low{color:var(--low)}.merge-title{margin-top:4px;font-size:13px;color:var(--ink)}.reasons{margin:10px 0 0;padding:0 0 0 18px;color:var(--muted)}.reasons li{margin:0 0 4px}.metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:0 0 14px}.metric{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);padding:8px 10px}.metric .n{font-family:var(--mono);font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}.metric .l{font-size:11px;color:var(--muted);margin-top:2px}.section{border-top:1px solid var(--line);padding:8px 0 4px}.section>summary{cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.07em;font-weight:600;padding:6px 0}.section>summary::-webkit-details-marker{display:none}.section>summary .count{font-family:var(--mono);letter-spacing:0;text-transform:none;border:1px solid var(--line);border-radius:999px;padding:0 7px;height:18px;display:inline-flex;align-items:center;font-size:11px}.kicker{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.08em;margin:16px 0 6px;font-weight:600}.chip{display:inline-flex;align-items:center;font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--line);margin:0 6px 6px 0;color:var(--muted);background:var(--surface)}.chip.blocker{color:var(--low);border-color:var(--low)}.chip.warning{color:var(--medium);border-color:var(--medium)}.chip.strong{color:var(--low);border-color:var(--low)}.chip.worth_exploring{color:var(--medium);border-color:var(--medium)}.chip.speculative{color:var(--muted);border-color:var(--line)}.chip.open{color:var(--high);border-color:color-mix(in srgb,var(--high) 50%,var(--line))}.file{font-family:var(--mono);font-size:12px;color:var(--accent)}.read-item,.finding,.residual{padding:8px 0;border-bottom:1px solid color-mix(in srgb,var(--line) 70%,transparent)}.read-item:last-child,.finding:last-child{border-bottom:0}.read-item.tour-current{background:color-mix(in srgb,var(--accent) 12%,var(--surface));border-color:var(--accent)}.tour-row{margin-top:8px;align-items:center}.field.dirty .chip-btn{height:32px}.muted{color:var(--muted);font-size:13px;line-height:1.45}.error{color:var(--low);padding:8px 12px;border:1px solid var(--low);background:color-mix(in srgb,var(--low) 10%,var(--surface));border-radius:var(--radius);display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.banner{padding:8px 12px;border-radius:var(--radius);border:1px solid var(--line);background:var(--surface);font-size:13px;line-height:1.45;display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.banner.warn{border-color:var(--medium);color:var(--medium)}.banner.stale{border-color:var(--low);color:var(--low)}.banner.whatif{border-color:var(--accent);align-items:center}.banner.whatif .btn{flex:0 0 auto;white-space:nowrap}.chip.whatif{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 55%,var(--line))}.whatif-hint{margin:10px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.banner .dismiss{background:transparent;border:0;color:inherit;cursor:pointer;height:auto;padding:0 2px;opacity:.7}.empty{padding:24px 8px;color:var(--muted);font-size:13px;line-height:1.55}.workspace-loading{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:220px;padding:48px 16px}.graph-walk-empty{flex:1;display:flex;flex-direction:column;justify-content:center;max-width:36rem;margin:0 auto}.empty ol{margin:12px 0 0 18px;padding:0}.empty code,code{font-family:var(--mono);font-size:12px;color:var(--accent)}.btn-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.pr-list{padding:16px;overflow:auto}.pr-toolbar{display:flex;gap:8px;align-items:flex-end;margin-bottom:14px}.pr-toolbar .field{flex:1}.pr-toolbar .field.provider{flex:0 0 140px}.scm-count{margin:0 0 12px;font-size:12px}.scm-login{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:10px 0;border-top:1px solid var(--line)}.scm-login:first-of-type{border-top:0;padding-top:0}.scm-login .btn-row{margin-top:0}.scm-login p{margin:2px 0 0}.oauth-code{font-size:13px;margin:0}.oauth-code code{font-size:14px;letter-spacing:.08em}.pr{border:1px solid var(--line);background:var(--surface);padding:12px 14px;border-radius:var(--radius-lg);margin-bottom:10px}.pr h3{margin:0 0 4px;font-size:14px;font-weight:600}.pr-meta{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center;margin:6px 0 10px}.pr-actions{display:flex;gap:8px;align-items:center}.settings{padding:24px;max-width:760px;overflow:auto;display:grid;gap:16px}.settings-card{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-lg);padding:16px;display:grid;gap:8px}.settings-card h2{font-size:14px;margin-bottom:2px}.settings label{font-size:12px;color:var(--muted);font-weight:500}.theme-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}.theme-swatch{border:1px solid var(--line);background:var(--bg);color:var(--ink);border-radius:var(--radius);padding:10px;text-align:left;cursor:pointer;height:auto;box-shadow:0 1px 8px var(--shadow)}.theme-swatch.active{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent),0 1px 8px var(--shadow)}.theme-swatch .swatch-bar{height:6px;border-radius:3px;margin-bottom:8px;background:linear-gradient(90deg,var(--accent),var(--high),var(--medium),var(--low))}.theme-swatch .name{font-size:13px;font-weight:600}.theme-swatch .group{font-size:11px;color:var(--muted)}.headline{white-space:pre-wrap;font-family:var(--mono);font-size:12px;color:var(--muted);margin:8px 0 0}.graph-modes{display:flex;gap:8px;align-items:center;padding:8px 14px;border-bottom:1px solid var(--line);background:var(--bg-2)}.seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;padding:2px;background:var(--surface)}.seg button,.graph-modes button{background:transparent;border:0;border-radius:999px;padding:4px 12px;color:var(--muted);cursor:pointer;height:26px}.seg button.active,.graph-modes button.active{background:var(--rail-active);color:var(--ink)}.legend{margin-left:auto;display:flex;gap:12px;color:var(--muted);font-size:11px}.legend i{display:inline-block;width:14px;height:2px;margin-right:6px;vertical-align:middle;background:var(--edge-cheap)}.legend i.exp{background:var(--edge-expensive)}.legend i.crit{background:var(--edge-critical);height:3px}.legend i.dash{border-top:2px dashed var(--muted);background:none;height:0}.legend i.seed{height:10px;width:10px;border-radius:2px;background:color-mix(in srgb,var(--medium) 70%,var(--node-bg))}.legend i.down{height:10px;width:10px;border-radius:2px;border:1px solid color-mix(in srgb,var(--accent) 45%,var(--node-line));background:var(--node-bg)}.inspector{position:absolute;top:12px;right:12px;z-index:5;width:300px;max-width:calc(100% - 24px);max-height:calc(100% - 24px);overflow-x:hidden;overflow-y:auto;overflow-wrap:break-word;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);padding:10px 12px;box-shadow:0 8px 24px var(--shadow);font-size:12px}.inspector .t{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.inspector .n,.inspector .file,.inspector .muted{overflow-wrap:break-word}.inspector .n{font-weight:600;margin:4px 0}.inspector-head{display:flex;align-items:flex-start;gap:8px}.inspector-roles{display:flex;flex-wrap:wrap;justify-content:flex-end;flex:1;gap:4px}.inspector-chip{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:1px 6px;border-radius:999px;border:1px solid var(--line);color:var(--muted);white-space:nowrap}.inspector-close{flex:0 0 auto;width:24px;height:24px;padding:0;border:1px solid var(--line);border-radius:var(--radius);background:transparent;color:var(--muted);font-size:16px;line-height:1;cursor:pointer}.inspector-close:hover{color:var(--ink)}.inspector-purpose{margin:6px 0 8px;color:var(--ink);font-size:12px;line-height:1.4}.inspector-layer{margin-top:4px;font-size:11px}.inspector-degree{font-size:11px}.inspector-path{margin:6px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.inspector-facts{margin:10px 0 0;padding-top:8px;border-top:1px solid var(--line)}.inspector-fact{display:grid;grid-template-columns:minmax(64px,92px) minmax(0,1fr);gap:8px;padding:3px 0;align-items:start}.inspector-fact dt{color:var(--muted);font-size:11px;margin:0}.inspector-fact dd{margin:0;overflow-wrap:break-word}.inspector-section{margin-top:10px;padding-top:8px;border-top:1px solid var(--line)}.inspector-section h3{margin:0 0 6px;display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.07em;font-weight:600}.inspector-section .count{font-family:var(--mono);letter-spacing:0;text-transform:none;border:1px solid var(--line);border-radius:999px;padding:0 7px;height:18px;display:inline-flex;align-items:center;font-size:11px}.inspector-section ul{list-style:none;margin:0;padding:0}.inspector-section li{padding:4px 0;border-bottom:1px solid color-mix(in srgb,var(--line) 70%,transparent)}.inspector-section li:last-child{border-bottom:0}.inspector-link-name{display:block;font-weight:600;overflow-wrap:break-word}.inspector-link-meta{display:block;color:var(--muted);font-size:11px}.lp-node{padding:8px 10px;border-radius:var(--radius);border:1px solid var(--node-line);background:var(--node-bg);width:208px;max-width:100%;height:64px;box-sizing:border-box;box-shadow:0 0 0 1px var(--shadow);overflow:visible;position:relative}.lp-node .t{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.lp-node .n{font-size:13px;font-weight:600;line-height:1.2;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow-wrap:anywhere}.lp-node.selected{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}.lp-node.role-seed{border-color:var(--medium);background:color-mix(in srgb,var(--medium) 14%,var(--node-bg))}.lp-node.role-downstream{border-color:color-mix(in srgb,var(--accent) 45%,var(--node-line))}.lp-node.role-untested{box-shadow:inset 3px 0 0 var(--low)}.lp-node.role-tested{box-shadow:inset 3px 0 0 var(--high)}.lp-node.role-contract{outline:1px dashed color-mix(in srgb,var(--accent) 50%,transparent)}.lp-node.dim{opacity:.38}.merge-box.compact{padding:6px 10px;min-width:92px;margin:0}.merge-box.compact .level{font-size:12px}.palette-scrim{position:fixed;top:0;right:0;bottom:0;left:0;background:color-mix(in srgb,var(--bg) 55%,transparent);z-index:40;display:grid;place-items:start center;padding-top:12vh}.palette{width:min(640px,calc(100vw - 32px));background:var(--surface);border:1px solid var(--line);border-radius:12px;box-shadow:0 18px 60px var(--shadow);overflow:hidden}.palette input{width:100%;border:0;border-bottom:1px solid var(--line);background:transparent;color:var(--ink);padding:14px 16px;font:inherit}.palette ul{list-style:none;margin:0;padding:6px;max-height:360px;overflow:auto}.palette li button{width:100%;display:flex;justify-content:space-between;gap:12px;text-align:left;background:transparent;border:0;color:var(--ink);padding:8px 10px;border-radius:8px;cursor:pointer}.palette li button.active,.palette li button:hover{background:var(--rail-active)}.palette-foot{padding:8px 12px 10px}.graph-search{position:relative;min-width:140px}.graph-search input{width:100%;background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:6px 8px;font:inherit}.graph-search-hits{position:absolute;z-index:5;left:0;right:0;top:calc(100% + 4px);background:var(--surface);border:1px solid var(--line);border-radius:8px;list-style:none;margin:0;padding:4px;max-height:240px;overflow:auto}.graph-search-hits button{width:100%;display:flex;justify-content:space-between;gap:8px;background:transparent;border:0;color:var(--ink);text-align:left;padding:6px 8px;cursor:pointer}.graph-search-hits button:hover{background:var(--rail-active)}.inspector-link{display:flex;flex-direction:column;width:100%;background:transparent;border:0;color:inherit;text-align:left;cursor:pointer;padding:0}.file-row{display:flex;flex-direction:column;gap:6px}.linkish{background:none;border:0;color:inherit;font:inherit;text-align:left;cursor:pointer;padding:0}.history-item,.check-item{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline;width:100%;background:transparent;border:0;color:inherit;font:inherit;text-align:left;padding:6px 0;cursor:pointer}.history-item.current{color:var(--accent)}.check-row{display:flex;gap:8px;align-items:center;margin:4px 0}.sparkline{display:flex;align-items:flex-end;gap:3px;height:36px;margin:8px 0}.sparkline i{flex:1;background:var(--muted);border-radius:2px 2px 0 0;min-width:4px}.sparkline i.high{background:var(--high)}.sparkline i.medium{background:var(--medium)}.sparkline i.low{background:var(--low)}.config-editor .field{display:flex;flex-direction:column;gap:4px;margin:8px 0}.config-editor input,.config-editor select{background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:6px 8px}.react-flow__node-load .react-flow__handle{width:8px;height:8px;border:none;background:transparent;opacity:0}.type-table{width:100%;border-collapse:collapse;font-size:12px}.type-table td{padding:3px 0}.type-table td:last-child{text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--muted)}@media(prefers-reduced-motion:reduce){.progress i{animation:none;width:100%}.progress.determinate i{width:var(--progress, 100%)}*{scroll-behavior:auto!important}}@media(max-width:960px){.app{grid-template-columns:56px 1fr}.brand-sub,.nav-item span,.theme-pick,.kbd-hint,.rail-foot .muted{display:none}.nav-item{justify-content:center;padding:10px}.content{grid-template-columns:1fr}.brief{border-right:0;border-bottom:1px solid var(--line);max-height:42vh}} diff --git a/src/loadpath/static/index.html b/src/loadpath/static/index.html index 608e9fe..d829347 100644 --- a/src/loadpath/static/index.html +++ b/src/loadpath/static/index.html @@ -17,8 +17,8 @@ - - + +

From 25f2b8a268a3a2170ce8d747baa5bb47c745510f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 09:10:32 +0000 Subject: [PATCH 3/3] Address PR review: unify permission ids and unstick index progress. View permission_classes now share node ids with extracted *Permission classes so the inspector and tests point at the same node. The graph tab shows the loading state while architecture is still hydrating. The progress e2e no longer blocks other API routes with a sleep, which was racing the poll assertion in CI. Co-authored-by: zord.lack.net --- src/loadpath/extractors/django.py | 20 +++++++++++++--- src/loadpath/index.py | 2 +- ...Vlmu5bb6.js => LayeredGraph3D-Dg13YVFZ.js} | 2 +- .../{index-X7ZCWUII.js => index-Cj5VBWfS.js} | 2 +- src/loadpath/static/index.html | 2 +- tests/e2e/test_ui_flows.py | 10 ++------ tests/unit/test_django_extractors.py | 23 +++++++++++++++++++ ui/src/App.tsx | 2 +- 8 files changed, 47 insertions(+), 16 deletions(-) rename src/loadpath/static/assets/{LayeredGraph3D-Vlmu5bb6.js => LayeredGraph3D-Dg13YVFZ.js} (99%) rename src/loadpath/static/assets/{index-X7ZCWUII.js => index-Cj5VBWfS.js} (94%) diff --git a/src/loadpath/extractors/django.py b/src/loadpath/extractors/django.py index 03fad5d..9a37982 100644 --- a/src/loadpath/extractors/django.py +++ b/src/loadpath/extractors/django.py @@ -767,9 +767,16 @@ def _view(self, node: ast.ClassDef) -> None: fs_q = fs if "." in fs and not fs.startswith("filter") else f"{self.app}.{fs.split('.')[-1]}" self.add_edge(view.id, node_id(NodeType.FORM, fs_q), EdgeType.CALLS, confidence=0.9) for perm in permissions: - pid = node_id(NodeType.PERMISSION, perm) + ident = self._permission_identity(perm) + pid = node_id(NodeType.PERMISSION, ident) self.graph.nodes.append( - Node(id=pid, type=NodeType.PERMISSION, name=perm, qualified_name=perm, extra={"from_view": qname}) + Node( + id=pid, + type=NodeType.PERMISSION, + name=perm.split(".")[-1], + qualified_name=ident, + extra={"from_view": qname}, + ) ) self.add_edge(view.id, pid, EdgeType.HAS_PERMISSION) for throttle in extra.get("throttles") or []: @@ -821,8 +828,15 @@ def _admin(self, node: ast.ClassDef) -> None: qname = f"{self.app}.{node.name}" self.add_node(NodeType.ADMIN, node.name, qname, node.lineno, _with_doc({"app": self.app}, node)) + def _permission_identity(self, perm: str) -> str: + """Local *Permission classes share an id with view.permission_classes.""" + short = perm.split(".")[-1] + if short.endswith("Permission"): + return f"{self.app}.{short}" + return short + def _permission_class(self, node: ast.ClassDef) -> None: - qname = f"{self.app}.{node.name}" + qname = self._permission_identity(node.name) self.add_node( NodeType.PERMISSION, node.name, diff --git a/src/loadpath/index.py b/src/loadpath/index.py index c130f02..b7f5460 100644 --- a/src/loadpath/index.py +++ b/src/loadpath/index.py @@ -23,7 +23,7 @@ PY_SKIP = {"migrations"} # still extract migrations, just not skip INDEX_EXTENSIONS = {".py", ".ts", ".tsx", ".js", ".jsx", ".html", ".htm", ".graphql", ".gql"} # Bump when extractor/stitch node identity changes so incremental indexes rebuild. -INDEX_REVISION = "15" +INDEX_REVISION = "16" _UPSERT_BATCH = 25 ProgressCallback = Callable[[dict[str, Any]], None] diff --git a/src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js b/src/loadpath/static/assets/LayeredGraph3D-Dg13YVFZ.js similarity index 99% rename from src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js rename to src/loadpath/static/assets/LayeredGraph3D-Dg13YVFZ.js index 092ec0e..8c57fdd 100644 --- a/src/loadpath/static/assets/LayeredGraph3D-Vlmu5bb6.js +++ b/src/loadpath/static/assets/LayeredGraph3D-Dg13YVFZ.js @@ -1,4 +1,4 @@ -import{r as un,l as tc,c as nc,a as ic,L as sc,j as ei,t as rc}from"./index-X7ZCWUII.js";/** +import{r as un,l as tc,c as nc,a as ic,L as sc,j as ei,t as rc}from"./index-Cj5VBWfS.js";/** * @license * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT diff --git a/src/loadpath/static/assets/index-X7ZCWUII.js b/src/loadpath/static/assets/index-Cj5VBWfS.js similarity index 94% rename from src/loadpath/static/assets/index-X7ZCWUII.js rename to src/loadpath/static/assets/index-Cj5VBWfS.js index 2b7ec6b..ca05674 100644 --- a/src/loadpath/static/assets/index-X7ZCWUII.js +++ b/src/loadpath/static/assets/index-Cj5VBWfS.js @@ -59,4 +59,4 @@ Error generating stack: `+m.message+` `,` +`).split(` `)),x=y.reduce((v,g)=>v.concat(...g),[]);return[y,x]}return[[],[]]},[t]);return L.useEffect(()=>{const p=(r==null?void 0:r.target)??ep,y=(r==null?void 0:r.actInsideInputWithModifier)??!0;if(t!==null){const x=_=>{var b,E;if(a.current=_.ctrlKey||_.metaKey||_.shiftKey||_.altKey,(!a.current||a.current&&!y)&&kg(_))return!1;const N=np(_.code,h);if(u.current.add(_[N]),tp(c,u.current,!1)){const I=((E=(b=_.composedPath)==null?void 0:b.call(_))==null?void 0:E[0])||_.target,w=(I==null?void 0:I.nodeName)==="BUTTON"||(I==null?void 0:I.nodeName)==="A";r.preventDefault!==!1&&(a.current||!w)&&_.preventDefault(),s(!0)}},v=_=>{const S=np(_.code,h);tp(c,u.current,!0)?(s(!1),u.current.clear()):u.current.delete(_[S]),_.key==="Meta"&&u.current.clear(),a.current=!1},g=()=>{u.current.clear(),s(!1)};return p==null||p.addEventListener("keydown",x),p==null||p.addEventListener("keyup",v),window.addEventListener("blur",g),window.addEventListener("contextmenu",g),()=>{p==null||p.removeEventListener("keydown",x),p==null||p.removeEventListener("keyup",v),window.removeEventListener("blur",g),window.removeEventListener("contextmenu",g)}}},[t,s]),o}function tp(t,r,o){return t.filter(s=>o||s.length===r.size).some(s=>s.every(a=>r.has(a)))}function np(t,r){return r.includes(t)?"code":"key"}const D_=()=>{const t=Ge();return L.useMemo(()=>({zoomIn:async r=>{const{panZoom:o}=t.getState();return o?o.scaleBy(1.2,r):!1},zoomOut:async r=>{const{panZoom:o}=t.getState();return o?o.scaleBy(1/1.2,r):!1},zoomTo:async(r,o)=>{const{panZoom:s}=t.getState();return s?s.scaleTo(r,o):!1},getZoom:()=>t.getState().transform[2],setViewport:async(r,o)=>{const{transform:[s,a,u],panZoom:c}=t.getState();return c?(await c.setViewport({x:r.x??s,y:r.y??a,zoom:r.zoom??u},o),!0):!1},getViewport:()=>{const[r,o,s]=t.getState().transform;return{x:r,y:o,zoom:s}},setCenter:async(r,o,s)=>t.getState().setCenter(r,o,s),fitBounds:async(r,o)=>{const{width:s,height:a,minZoom:u,maxZoom:c,panZoom:h}=t.getState(),p=Pc(r,s,a,u,c,(o==null?void 0:o.padding)??.1);return h?(await h.setViewport(p,{duration:o==null?void 0:o.duration,ease:o==null?void 0:o.ease,interpolate:o==null?void 0:o.interpolate}),!0):!1},screenToFlowPosition:(r,o={})=>{const{transform:s,snapGrid:a,snapToGrid:u,domNode:c}=t.getState();if(!c)return r;const{x:h,y:p}=c.getBoundingClientRect(),y={x:r.x-h,y:r.y-p},x=o.snapGrid??a,v=o.snapToGrid??u;return xs(y,s,v,x)},flowToScreenPosition:r=>{const{transform:o,domNode:s}=t.getState();if(!s)return r;const{x:a,y:u}=s.getBoundingClientRect(),c=ri(r,o);return{x:c.x+a,y:c.y+u}}}),[])};function Ug(t,r){const o=[],s=new Map,a=[];for(const u of t)if(u.type==="add"){a.push(u);continue}else if(u.type==="remove"||u.type==="replace")s.set(u.id,[u]);else{const c=s.get(u.id);c?c.push(u):s.set(u.id,[u])}for(const u of r){const c=s.get(u.id);if(!c){o.push(u);continue}if(c[0].type==="remove")continue;if(c[0].type==="replace"){o.push({...c[0].item});continue}const h={...u};for(const p of c)O_(p,h);o.push(h)}return a.length&&a.forEach(u=>{u.index!==void 0?o.splice(u.index,0,{...u.item}):o.push({...u.item})}),o}function O_(t,r){switch(t.type){case"select":{r.selected=t.selected;break}case"position":{typeof t.position<"u"&&(r.position=t.position),typeof t.dragging<"u"&&(r.dragging=t.dragging);break}case"dimensions":{typeof t.dimensions<"u"&&(r.measured={...t.dimensions},t.setAttributes&&((t.setAttributes===!0||t.setAttributes==="width")&&(r.width=t.dimensions.width),(t.setAttributes===!0||t.setAttributes==="height")&&(r.height=t.dimensions.height))),typeof t.resizing=="boolean"&&(r.resizing=t.resizing);break}}}function F_(t,r){return Ug(t,r)}function H_(t,r){return Ug(t,r)}function ao(t,r){return{id:t,type:"select",selected:r}}function Ko(t,r=new Set,o=!1){const s=[];for(const[a,u]of t){const c=r.has(a);!(u.selected===void 0&&!c)&&u.selected!==c&&(o&&(u.selected=c),s.push(ao(u.id,c)))}return s}function rp({items:t=[],lookup:r}){var a;const o=[],s=new Map(t.map(u=>[u.id,u]));for(const[u,c]of t.entries()){const h=r.get(c.id),p=((a=h==null?void 0:h.internals)==null?void 0:a.userNode)??h;p!==void 0&&p!==c&&o.push({id:c.id,item:c,type:"replace"}),p===void 0&&o.push({item:c,type:"add",index:u})}for(const[u]of r)s.get(u)===void 0&&o.push({id:u,type:"remove"});return o}function op(t){return{id:t.id,type:"remove"}}const B_=xg();function V_(t,r,o={}){return b1(t,r,{...o,onError:o.onError??B_})}const ip=t=>d1(t),W_=t=>pg(t);function Gg(t){return L.forwardRef(t)}const Yg=typeof window<"u"?L.useLayoutEffect:L.useEffect;function sp(t){const[r,o]=L.useState(BigInt(0)),[s]=L.useState(()=>U_(()=>o(a=>a+BigInt(1))));return Yg(()=>{const a=s.get();a.length&&(t(a),s.reset())},[r]),s}function U_(t){let r=[];return{get:()=>r,reset:()=>{r=[]},push:o=>{r.push(o),t()}}}const Xg=L.createContext(null);function G_({children:t}){const r=Ge(),o=L.useCallback(h=>{const{nodes:p=[],setNodes:y,hasDefaultNodes:x,onNodesChange:v,nodeLookup:g,fitViewQueued:_,onNodesChangeMiddlewareMap:S}=r.getState();let N=p;for(const E of h)N=typeof E=="function"?E(N):E;let b=rp({items:N,lookup:g});for(const E of S.values())b=E(b);x&&y(N),b.length>0?v==null||v(b):_&&window.requestAnimationFrame(()=>{const{fitViewQueued:E,nodes:I,setNodes:w}=r.getState();E&&w(I)})},[]),s=sp(o),a=L.useCallback(h=>{const{edges:p=[],setEdges:y,hasDefaultEdges:x,onEdgesChange:v,edgeLookup:g}=r.getState();let _=p;for(const S of h)_=typeof S=="function"?S(_):S;x?y(_):v&&v(rp({items:_,lookup:g}))},[]),u=sp(a),c=L.useMemo(()=>({nodeQueue:s,edgeQueue:u}),[]);return d.jsx(Xg.Provider,{value:c,children:t})}function Y_(){const t=L.useContext(Xg);if(!t)throw new Error("useBatchContext must be used within a BatchProvider");return t}const X_=t=>!!t.panZoom;function ll(){const t=D_(),r=Ge(),o=Y_(),s=De(X_),a=L.useMemo(()=>{const u=v=>r.getState().nodeLookup.get(v),c=v=>{o.nodeQueue.push(v)},h=v=>{o.edgeQueue.push(v)},p=v=>{var E,I;const{nodeLookup:g,nodeOrigin:_}=r.getState(),S=ip(v)?v:g.get(v.id),N=S.parentId?_g(S.position,S.measured,S.parentId,g,_):S.position,b={...S,position:N,width:((E=S.measured)==null?void 0:E.width)??S.width,height:((I=S.measured)==null?void 0:I.height)??S.height};return cs(b)},y=(v,g,_={replace:!1})=>{c(S=>S.map(N=>{if(N.id===v){const b=typeof g=="function"?g(N):g;return _.replace&&ip(b)?b:{...N,...b}}return N}))},x=(v,g,_={replace:!1})=>{h(S=>S.map(N=>{if(N.id===v){const b=typeof g=="function"?g(N):g;return _.replace&&W_(b)?b:{...N,...b}}return N}))};return{getNodes:()=>r.getState().nodes.map(v=>({...v})),getNode:v=>{var g;return(g=u(v))==null?void 0:g.internals.userNode},getInternalNode:u,getEdges:()=>{const{edges:v=[]}=r.getState();return v.map(g=>({...g}))},getEdge:v=>r.getState().edgeLookup.get(v),setNodes:c,setEdges:h,addNodes:v=>{const g=Array.isArray(v)?v:[v];o.nodeQueue.push(_=>[..._,...g])},addEdges:v=>{const g=Array.isArray(v)?v:[v];o.edgeQueue.push(_=>[..._,...g])},toObject:()=>{const{nodes:v=[],edges:g=[],transform:_}=r.getState(),[S,N,b]=_;return{nodes:v.map(E=>({...E})),edges:g.map(E=>({...E})),viewport:{x:S,y:N,zoom:b}}},deleteElements:async({nodes:v=[],edges:g=[]})=>{const{nodes:_,edges:S,onNodesDelete:N,onEdgesDelete:b,triggerNodeChanges:E,triggerEdgeChanges:I,onDelete:w,onBeforeDelete:j}=r.getState(),{nodes:A,edges:$}=await m1({nodesToRemove:v,edgesToRemove:g,nodes:_,edges:S,onBeforeDelete:j}),F=$.length>0,Y=A.length>0;if(F){const q=$.map(op);b==null||b($),I(q)}if(Y){const q=A.map(op);N==null||N(A),E(q)}return(Y||F)&&(w==null||w({nodes:A,edges:$})),{deletedNodes:A,deletedEdges:$}},getIntersectingNodes:(v,g=!0,_)=>{const S=Ph(v),N=S?v:p(v),b=_!==void 0;return N?(_||r.getState().nodes).filter(E=>{const I=r.getState().nodeLookup.get(E.id);if(I&&!S&&(E.id===v.id||!I.internals.positionAbsolute))return!1;const w=cs(b?E:I),j=Ga(w,N);return g&&j>0||j>=w.width*w.height||j>=N.width*N.height}):[]},isNodeIntersecting:(v,g,_=!0)=>{const N=Ph(v)?v:p(v);if(!N)return!1;const b=Ga(N,g);return _&&b>0||b>=g.width*g.height||b>=N.width*N.height},updateNode:y,updateNodeData:(v,g,_={replace:!1})=>{y(v,S=>{const N=typeof g=="function"?g(S):g;return _.replace?{...S,data:N}:{...S,data:{...S.data,...N}}},_)},updateEdge:x,updateEdgeData:(v,g,_={replace:!1})=>{x(v,S=>{const N=typeof g=="function"?g(S):g;return _.replace?{...S,data:N}:{...S,data:{...S.data,...N}}},_)},getNodesBounds:v=>{const{nodeLookup:g,nodeOrigin:_}=r.getState();return f1(v,{nodeLookup:g,nodeOrigin:_})},getHandleConnections:({type:v,id:g,nodeId:_})=>{var S;return Array.from(((S=r.getState().connectionLookup.get(`${_}-${v}${g?`-${g}`:""}`))==null?void 0:S.values())??[])},getNodeConnections:({type:v,handleId:g,nodeId:_})=>{var S;return Array.from(((S=r.getState().connectionLookup.get(`${_}${v?g?`-${v}-${g}`:`-${v}`:""}`))==null?void 0:S.values())??[])},fitView:async v=>{const g=r.getState().fitViewResolver??x1();return r.setState({fitViewQueued:!0,fitViewOptions:v,fitViewResolver:g}),o.nodeQueue.push(_=>[..._]),g.promise}}},[]);return L.useMemo(()=>({...a,...t,viewportInitialized:s}),[s])}const ap=t=>t.selected,q_=typeof window<"u"?window:void 0;function K_({deleteKeyCode:t,multiSelectionKeyCode:r}){const o=Ge(),{deleteElements:s}=ll(),a=fs(t,{actInsideInputWithModifier:!1}),u=fs(r,{target:q_});L.useEffect(()=>{if(a){const{edges:c,nodes:h}=o.getState();s({nodes:h.filter(ap),edges:c.filter(ap)}),o.setState({nodesSelectionActive:!1})}},[a]),L.useEffect(()=>{o.setState({multiSelectionActive:u})},[u])}function Q_(t){const r=Ge();L.useEffect(()=>{const o=()=>{var a,u,c,h;if(!t.current||!(((u=(a=t.current).checkVisibility)==null?void 0:u.call(a))??!0))return!1;const s=Ic(t.current);(s.height===0||s.width===0)&&((h=(c=r.getState()).onError)==null||h.call(c,"004",wn.error004())),r.setState({width:s.width||500,height:s.height||500})};if(t.current){o(),window.addEventListener("resize",o);const s=new ResizeObserver(()=>o());return s.observe(t.current),()=>{window.removeEventListener("resize",o),s&&t.current&&s.unobserve(t.current)}}},[])}const ul={position:"absolute",width:"100%",height:"100%",top:0,left:0},Z_=t=>({userSelectionActive:t.userSelectionActive,lib:t.lib,connectionInProgress:t.connection.inProgress});function J_({onPaneContextMenu:t,zoomOnScroll:r=!0,zoomOnPinch:o=!0,panOnScroll:s=!1,panActivationKeyPressed:a,panOnScrollSpeed:u=.5,panOnScrollMode:c=co.Free,zoomOnDoubleClick:h=!0,panOnDrag:p=!0,defaultViewport:y,translateExtent:x,minZoom:v,maxZoom:g,zoomActivationKeyCode:_,preventScrolling:S=!0,children:N,noWheelClassName:b,noPanClassName:E,onViewportChange:I,isControlledViewport:w,paneClickDistance:j,selectionOnDrag:A}){const $=Ge(),F=L.useRef(null),{userSelectionActive:Y,lib:q,connectionInProgress:re}=De(Z_,Qe),J=fs(_),te=L.useRef();Q_(F);const Q=L.useCallback(C=>{I==null||I({x:C[0],y:C[1],zoom:C[2]}),w||$.setState({transform:C})},[I,w]);return L.useEffect(()=>{if(F.current){te.current=n_({domNode:F.current,minZoom:v,maxZoom:g,translateExtent:x,viewport:y,onDraggingChange:U=>$.setState(M=>M.paneDragging===U?M:{paneDragging:U}),onPanZoomStart:(U,M)=>{const{onViewportChangeStart:D,onMoveStart:H}=$.getState();H==null||H(U,M),D==null||D(M)},onPanZoom:(U,M)=>{const{onViewportChange:D,onMove:H}=$.getState();H==null||H(U,M),D==null||D(M)},onPanZoomEnd:(U,M)=>{const{onViewportChangeEnd:D,onMoveEnd:H}=$.getState();H==null||H(U,M),D==null||D(M)}});const{x:C,y:V,zoom:W}=te.current.getViewport();return $.setState({panZoom:te.current,transform:[C,V,W],domNode:F.current.closest(".react-flow")}),()=>{var U;(U=te.current)==null||U.destroy()}}},[]),L.useEffect(()=>{var C;(C=te.current)==null||C.update({onPaneContextMenu:t,zoomOnScroll:r,zoomOnPinch:o,panOnScroll:s,panActivationKeyPressed:a,panOnScrollSpeed:u,panOnScrollMode:c,zoomOnDoubleClick:h,panOnDrag:p,zoomActivationKeyPressed:J,preventScrolling:S,noPanClassName:E,userSelectionActive:Y,noWheelClassName:b,lib:q,onTransformChange:Q,connectionInProgress:re,selectionOnDrag:A,paneClickDistance:j})},[t,r,o,s,a,u,c,h,p,J,S,E,Y,b,q,Q,re,A,j]),d.jsx("div",{className:"react-flow__renderer",ref:F,style:ul,children:N})}const eS=t=>({userSelectionActive:t.userSelectionActive,userSelectionRect:t.userSelectionRect});function tS(){const{userSelectionActive:t,userSelectionRect:r}=De(eS,Qe);return t&&r?d.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:r.width,height:r.height,transform:`translate(${r.x}px, ${r.y}px)`}}):null}const ec=(t,r)=>o=>{o.target===r.current&&(t==null||t(o))},nS=t=>({userSelectionActive:t.userSelectionActive,elementsSelectable:t.elementsSelectable,dragging:t.paneDragging,panBy:t.panBy,autoPanSpeed:t.autoPanSpeed});function rS({isSelecting:t,selectionKeyPressed:r,selectionMode:o=ls.Full,panOnDrag:s,autoPanOnSelection:a,paneClickDistance:u,selectionOnDrag:c,onSelectionStart:h,onSelectionEnd:p,onPaneClick:y,onPaneContextMenu:x,onPaneScroll:v,onPaneMouseEnter:g,onPaneMouseMove:_,onPaneMouseLeave:S,children:N}){const b=L.useRef(0),E=Ge(),{userSelectionActive:I,elementsSelectable:w,dragging:j,panBy:A,autoPanSpeed:$}=De(nS,Qe),F=w&&(t||I),Y=L.useRef(null),q=L.useRef(),re=L.useRef(new Set),J=L.useRef(new Set),te=L.useRef(!1),Q=L.useRef(!1),C=L.useRef({x:0,y:0}),V=L.useRef(!1),W=Z=>{if(Q.current||te.current||E.getState().connection.inProgress){Q.current=!1,te.current=!1;return}y==null||y(Z),E.getState().resetSelectedElements(),E.setState({nodesSelectionActive:!1})},U=Z=>{if(Array.isArray(s)&&(s!=null&&s.includes(2))){Z.preventDefault();return}x==null||x(Z)},M=v?Z=>v(Z):void 0,D=Z=>{Q.current&&(Z.stopPropagation(),Q.current=!1)},H=Z=>{var Le,nt;if(Z.pointerType==="touch"&&s!==!1&&!r)return;const{domNode:se,transform:me}=E.getState();if(q.current=se==null?void 0:se.getBoundingClientRect(),!q.current)return;const Ne=Z.target===Y.current;if(!Ne&&!!Z.target.closest(".nokey")||!t||!(c&&Ne||r)||Z.button!==0||!Z.isPrimary)return;(nt=(Le=Z.target)==null?void 0:Le.setPointerCapture)==null||nt.call(Le,Z.pointerId),Q.current=!1;const{x:Pe,y:ue}=xn(Z.nativeEvent,q.current),je=xs({x:Pe,y:ue},me);E.setState({userSelectionRect:{width:0,height:0,startX:je.x,startY:je.y,x:Pe,y:ue}}),Ne||(Z.stopPropagation(),Z.preventDefault())};function R(Z,se){const{userSelectionRect:me}=E.getState();if(!me)return;const{transform:Ne,nodeLookup:we,edgeLookup:ve,connectionLookup:Pe,triggerNodeChanges:ue,triggerEdgeChanges:je,defaultEdgeOptions:Le}=E.getState(),nt={x:me.startX,y:me.startY},{x:lt,y:ut}=ri(nt,Ne),Ye={startX:nt.x,startY:nt.y,x:Zmt.id)),J.current=new Set;const gt=(Le==null?void 0:Le.selectable)??!0;for(const mt of re.current){const Ct=Pe.get(mt);if(Ct)for(const{edgeId:ct}of Ct.values()){const et=ve.get(ct);et&&(et.selectable??gt)&&J.current.add(ct)}}if(!Ih(wt,re.current)){const mt=Ko(we,re.current,!0);ue(mt)}if(!Ih(Yt,J.current)){const mt=Ko(ve,J.current);je(mt)}E.setState({userSelectionRect:Ye,userSelectionActive:!0,nodesSelectionActive:!1})}function z(){if(!a||!q.current)return;const[Z,se]=Mc(C.current,q.current,$);A({x:Z,y:se}).then(me=>{if(!Q.current||!me){b.current=requestAnimationFrame(z);return}const{x:Ne,y:we}=C.current;R(Ne,we),b.current=requestAnimationFrame(z)})}const ne=()=>{cancelAnimationFrame(b.current),b.current=0,V.current=!1};L.useEffect(()=>()=>ne(),[]);const oe=Z=>{const{userSelectionRect:se,transform:me,resetSelectedElements:Ne}=E.getState();if(!q.current||!se)return;const{x:we,y:ve}=xn(Z.nativeEvent,q.current);C.current={x:we,y:ve};const Pe=ri({x:se.startX,y:se.startY},me);if(!Q.current){const ue=r?0:u;if(Math.hypot(we-Pe.x,ve-Pe.y)<=ue)return;Ne(),h==null||h(Z)}Q.current=!0,V.current||(z(),V.current=!0),R(we,ve)},fe=Z=>{var se,me;if(!F){Z.target===Y.current&&E.getState().connection.inProgress&&(te.current=!0);return}Z.button===0&&((me=(se=Z.target)==null?void 0:se.releasePointerCapture)==null||me.call(se,Z.pointerId),!I&&Z.target===Y.current&&E.getState().userSelectionRect&&(W==null||W(Z)),E.setState({userSelectionActive:!1,userSelectionRect:null}),Q.current&&(p==null||p(Z),E.setState({nodesSelectionActive:re.current.size>0})),ne())},he=Z=>{var se,me;(me=(se=Z.target)==null?void 0:se.releasePointerCapture)==null||me.call(se,Z.pointerId),ne()},pe=s===!0||Array.isArray(s)&&s.includes(0);return d.jsxs("div",{className:ot(["react-flow__pane",{draggable:pe,dragging:j,selection:t}]),onClick:F?void 0:ec(W,Y),onContextMenu:ec(U,Y),onWheel:ec(M,Y),onPointerEnter:F?void 0:g,onPointerMove:F?oe:_,onPointerUp:fe,onPointerCancel:F?he:void 0,onPointerDownCapture:F?H:void 0,onClickCapture:F?D:void 0,onPointerLeave:S,ref:Y,style:ul,children:[N,d.jsx(tS,{})]})}function vc({id:t,store:r,unselect:o=!1,nodeRef:s}){const{addSelectedNodes:a,unselectNodesAndEdges:u,multiSelectionActive:c,nodeLookup:h,onError:p}=r.getState(),y=h.get(t);if(!y){p==null||p("012",wn.error012(t));return}r.setState({nodesSelectionActive:!1}),y.selected?(o||y.selected&&c)&&(u({nodes:[y],edges:[]}),requestAnimationFrame(()=>{var x;return(x=s==null?void 0:s.current)==null?void 0:x.blur()})):a([t])}function qg({nodeRef:t,disabled:r=!1,noDragClassName:o,handleSelector:s,nodeId:a,isSelectable:u,nodeClickDistance:c}){const h=Ge(),[p,y]=L.useState(!1),x=L.useRef();return L.useEffect(()=>{if(!r)return x.current=B1({getStoreItems:()=>h.getState(),onNodeMouseDown:v=>{vc({id:v,store:h,nodeRef:t})},onDragStart:()=>{y(!0)},onDragStop:()=>{y(!1)}}),()=>{var v;(v=x.current)==null||v.destroy(),x.current=void 0}},[r,h,t]),L.useEffect(()=>{r||!t.current||!x.current||x.current.update({noDragClassName:o,handleSelector:s,domNode:t.current,isSelectable:u,nodeId:a,nodeClickDistance:c})},[o,s,r,u,t,a,c]),p}const oS=t=>r=>r.selected&&(r.draggable||t&&typeof r.draggable>"u");function Kg(){const t=Ge();return L.useCallback(o=>{const{nodeExtent:s,snapToGrid:a,snapGrid:u,nodesDraggable:c,onError:h,updateNodePositions:p,nodeLookup:y,nodeOrigin:x}=t.getState(),v=new Map,g=oS(c),_=a?u[0]:5,S=a?u[1]:5,N=o.direction.x*_*o.factor,b=o.direction.y*S*o.factor;for(const[,E]of y){if(!g(E))continue;let I={x:E.internals.positionAbsolute.x+N,y:E.internals.positionAbsolute.y+b};a&&(I=vs(I,u));const{position:w,positionAbsolute:j}=gg({nodeId:E.id,nextPosition:I,nodeLookup:y,nodeExtent:s,nodeOrigin:x,onError:h});E.position=w,E.internals.positionAbsolute=j,v.set(E.id,E)}p(v)},[])}const zc=L.createContext(null),iS=zc.Provider;zc.Consumer;const Qg=()=>L.useContext(zc),sS=t=>({connectOnClick:t.connectOnClick,noPanClassName:t.noPanClassName,rfId:t.rfId}),Zg=L.createContext(null);function aS({children:t}){const r=De(sS,Qe);return d.jsx(Zg.Provider,{value:r,children:t})}function lS(){const t=L.useContext(Zg);if(!t)throw new Error("useHandleConfig must be used within a HandleConfigProvider");return t}const uS={connectingFrom:!1,connectingTo:!1,clickConnecting:!1,isPossibleEndHandle:!0,connectionInProcess:!1,clickConnectionInProcess:!1,valid:!1},cS=(t,r,o)=>s=>{const{connectionClickStartHandle:a,connectionMode:u,connection:c}=s,{fromHandle:h,toHandle:p,isValid:y}=c;if(!h&&!a)return uS;const x=(p==null?void 0:p.nodeId)===t&&(p==null?void 0:p.id)===r&&(p==null?void 0:p.type)===o;return{connectingFrom:(h==null?void 0:h.nodeId)===t&&(h==null?void 0:h.id)===r&&(h==null?void 0:h.type)===o,connectingTo:x,clickConnecting:(a==null?void 0:a.nodeId)===t&&(a==null?void 0:a.id)===r&&(a==null?void 0:a.type)===o,isPossibleEndHandle:u===ti.Strict?(h==null?void 0:h.type)!==o:t!==(h==null?void 0:h.nodeId)||r!==(h==null?void 0:h.id),connectionInProcess:!!h,clickConnectionInProcess:!!a,valid:x&&y}};function dS({type:t="source",position:r=ke.Top,isValidConnection:o,isConnectable:s=!0,isConnectableStart:a=!0,isConnectableEnd:u=!0,id:c,onConnect:h,children:p,className:y,onMouseDown:x,onTouchStart:v,...g},_){var V,W;const S=c||null,N=t==="target",b=Ge(),E=Qg(),{connectOnClick:I,noPanClassName:w,rfId:j}=lS(),{connectingFrom:A,connectingTo:$,clickConnecting:F,isPossibleEndHandle:Y,connectionInProcess:q,clickConnectionInProcess:re,valid:J}=De(cS(E,S,t),Qe);E||(W=(V=b.getState()).onError)==null||W.call(V,"010",wn.error010());const te=U=>{const{defaultEdgeOptions:M,onConnect:D,hasDefaultEdges:H}=b.getState(),R={...M,...U};if(H){const{edges:z,setEdges:ne,onError:oe}=b.getState();ne(V_(R,z,{onError:oe}))}D==null||D(R),h==null||h(R)},Q=U=>{if(!E)return;const M=Ng(U.nativeEvent);if(a&&(M&&U.button===0||!M)){const D=b.getState();yc.onPointerDown(U.nativeEvent,{handleDomNode:U.currentTarget,autoPanOnConnect:D.autoPanOnConnect,connectionMode:D.connectionMode,connectionRadius:D.connectionRadius,domNode:D.domNode,nodeLookup:D.nodeLookup,lib:D.lib,isTarget:N,handleId:S,nodeId:E,flowId:D.rfId,panBy:D.panBy,cancelConnection:D.cancelConnection,onConnectStart:D.onConnectStart,onConnectEnd:(...H)=>{var R,z;return(z=(R=b.getState()).onConnectEnd)==null?void 0:z.call(R,...H)},updateConnection:D.updateConnection,onConnect:te,isValidConnection:o||((...H)=>{var R,z;return((z=(R=b.getState()).isValidConnection)==null?void 0:z.call(R,...H))??!0}),getTransform:()=>b.getState().transform,getFromHandle:()=>b.getState().connection.fromHandle,autoPanSpeed:D.autoPanSpeed,dragThreshold:D.connectionDragThreshold})}M?x==null||x(U):v==null||v(U)},C=U=>{const{onClickConnectStart:M,onClickConnectEnd:D,connectionClickStartHandle:H,connectionMode:R,isValidConnection:z,lib:ne,rfId:oe,nodeLookup:fe,connection:he}=b.getState();if(!E||!H&&!a)return;if(!H){M==null||M(U.nativeEvent,{nodeId:E,handleId:S,handleType:t}),b.setState({connectionClickStartHandle:{nodeId:E,type:t,id:S}});return}const pe=Sg(U.target),Z=o||z,{connection:se,isValid:me}=yc.isValid(U.nativeEvent,{handle:{nodeId:E,id:S,type:t},connectionMode:R,fromNodeId:H.nodeId,fromHandleId:H.id||null,fromType:H.type,isValidConnection:Z,flowId:oe,doc:pe,lib:ne,nodeLookup:fe});me&&se&&te(se);const Ne=structuredClone(he);delete Ne.inProgress,Ne.toPosition=Ne.toHandle?Ne.toHandle.position:null,D==null||D(U,Ne),b.setState({connectionClickStartHandle:null})};return d.jsx("div",{"data-handleid":S,"data-nodeid":E,"data-handlepos":r,"data-id":`${j}-${E}-${S}-${t}`,className:ot(["react-flow__handle",`react-flow__handle-${r}`,"nodrag",w,y,{source:!N,target:N,connectable:s,connectablestart:a,connectableend:u,clickconnecting:F,connectingfrom:A,connectingto:$,valid:J,connectionindicator:s&&(!q||Y)&&(q||re?u:a)}]),onMouseDown:Q,onTouchStart:Q,onClick:I?C:void 0,ref:_,...g,children:p})}const ii=L.memo(Gg(dS));function fS({data:t,isConnectable:r,sourcePosition:o=ke.Bottom}){return d.jsxs(d.Fragment,{children:[t==null?void 0:t.label,d.jsx(ii,{type:"source",position:o,isConnectable:r})]})}function hS({data:t,isConnectable:r,targetPosition:o=ke.Top,sourcePosition:s=ke.Bottom}){return d.jsxs(d.Fragment,{children:[d.jsx(ii,{type:"target",position:o,isConnectable:r}),t==null?void 0:t.label,d.jsx(ii,{type:"source",position:s,isConnectable:r})]})}function pS(){return null}function gS({data:t,isConnectable:r,targetPosition:o=ke.Top}){return d.jsxs(d.Fragment,{children:[d.jsx(ii,{type:"target",position:o,isConnectable:r}),t==null?void 0:t.label]})}const Xa={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},lp={input:fS,default:hS,output:gS,group:pS};function mS(t){var r,o,s,a;return t.internals.handleBounds===void 0?{width:t.width??t.initialWidth??((r=t.style)==null?void 0:r.width),height:t.height??t.initialHeight??((o=t.style)==null?void 0:o.height)}:{width:t.width??((s=t.style)==null?void 0:s.width),height:t.height??((a=t.style)==null?void 0:a.height)}}const yS=t=>{const{width:r,height:o,x:s,y:a}=ys(t.nodeLookup,{filter:u=>!!u.selected});return{width:vn(r)?r:null,height:vn(o)?o:null,userSelectionActive:t.userSelectionActive,transformString:`translate(${t.transform[0]}px,${t.transform[1]}px) scale(${t.transform[2]}) translate(${s}px,${a}px)`}};function vS({onSelectionContextMenu:t,noPanClassName:r,disableKeyboardA11y:o}){const s=Ge(),{width:a,height:u,transformString:c,userSelectionActive:h}=De(yS,Qe),p=Kg(),y=L.useRef(null);L.useEffect(()=>{var _;o||(_=y.current)==null||_.focus({preventScroll:!0})},[o]);const x=!h&&a!==null&&u!==null;if(qg({nodeRef:y,disabled:!x}),!x)return null;const v=t?_=>{const S=s.getState().nodes.filter(N=>N.selected);t(_,S)}:void 0,g=_=>{Object.prototype.hasOwnProperty.call(Xa,_.key)&&(_.preventDefault(),p({direction:Xa[_.key],factor:_.shiftKey?4:1}))};return d.jsx("div",{className:ot(["react-flow__nodesselection","react-flow__container",r]),style:{transform:c},children:d.jsx("div",{ref:y,className:"react-flow__nodesselection-rect",onContextMenu:v,tabIndex:o?void 0:-1,onKeyDown:o?void 0:g,style:{width:a,height:u}})})}const up=typeof window<"u"?window:void 0,xS=t=>({nodesSelectionActive:t.nodesSelectionActive,userSelectionActive:t.userSelectionActive});function Jg({children:t,onPaneClick:r,onPaneMouseEnter:o,onPaneMouseMove:s,onPaneMouseLeave:a,onPaneContextMenu:u,onPaneScroll:c,paneClickDistance:h,deleteKeyCode:p,selectionKeyCode:y,selectionOnDrag:x,selectionMode:v,onSelectionStart:g,onSelectionEnd:_,multiSelectionKeyCode:S,panActivationKeyCode:N,zoomActivationKeyCode:b,elementsSelectable:E,zoomOnScroll:I,zoomOnPinch:w,panOnScroll:j,panOnScrollSpeed:A,panOnScrollMode:$,zoomOnDoubleClick:F,panOnDrag:Y,autoPanOnSelection:q,defaultViewport:re,translateExtent:J,minZoom:te,maxZoom:Q,preventScrolling:C,onSelectionContextMenu:V,noWheelClassName:W,noPanClassName:U,disableKeyboardA11y:M,onViewportChange:D,isControlledViewport:H}){const{nodesSelectionActive:R,userSelectionActive:z}=De(xS,Qe),ne=fs(y,{target:up}),oe=fs(N,{target:up}),fe=oe||Y,he=oe||j,pe=x&&fe!==!0,Z=ne||z||pe;return K_({deleteKeyCode:p,multiSelectionKeyCode:S}),d.jsx(J_,{onPaneContextMenu:u,elementsSelectable:E,zoomOnScroll:I,zoomOnPinch:w,panOnScroll:he,panActivationKeyPressed:oe,panOnScrollSpeed:A,panOnScrollMode:$,zoomOnDoubleClick:F,panOnDrag:!ne&&fe,defaultViewport:re,translateExtent:J,minZoom:te,maxZoom:Q,zoomActivationKeyCode:b,preventScrolling:C,noWheelClassName:W,noPanClassName:U,onViewportChange:D,isControlledViewport:H,paneClickDistance:h,selectionOnDrag:pe,children:d.jsxs(rS,{onSelectionStart:g,onSelectionEnd:_,onPaneClick:r,onPaneMouseEnter:o,onPaneMouseMove:s,onPaneMouseLeave:a,onPaneContextMenu:u,onPaneScroll:c,panOnDrag:fe,autoPanOnSelection:q,isSelecting:!!Z,selectionMode:v,selectionKeyPressed:ne,paneClickDistance:h,selectionOnDrag:pe,children:[t,R&&d.jsx(vS,{onSelectionContextMenu:V,noPanClassName:U,disableKeyboardA11y:M})]})})}Jg.displayName="FlowRenderer";const wS=L.memo(Jg),_S=t=>r=>t?Cc(r.nodeLookup,{x:0,y:0,width:r.width,height:r.height},r.transform,!0).map(o=>o.id):Array.from(r.nodeLookup.keys());function SS(t){return De(L.useCallback(_S(t),[t]),Qe)}const kS=t=>t.updateNodeInternals;function NS(){const t=De(kS),[r]=L.useState(()=>typeof ResizeObserver>"u"?null:new ResizeObserver(o=>{const s=new Map;o.forEach(a=>{const u=a.target.getAttribute("data-id");s.set(u,{id:u,nodeElement:a.target,force:!0})}),t(s)}));return L.useEffect(()=>()=>{r==null||r.disconnect()},[r]),r}function jS({node:t,nodeType:r,hasDimensions:o,resizeObserver:s}){const a=Ge(),u=L.useRef(null),c=L.useRef(null),h=L.useRef(t.sourcePosition),p=L.useRef(t.targetPosition),y=L.useRef(r),x=o&&!!t.internals.handleBounds;return L.useEffect(()=>{u.current&&!t.hidden&&(!x||c.current!==u.current)&&(c.current&&(s==null||s.unobserve(c.current)),s==null||s.observe(u.current),c.current=u.current)},[x,t.hidden]),L.useEffect(()=>()=>{c.current&&(s==null||s.unobserve(c.current),c.current=null)},[]),L.useEffect(()=>{if(u.current){const v=y.current!==r,g=h.current!==t.sourcePosition,_=p.current!==t.targetPosition;(v||g||_)&&(y.current=r,h.current=t.sourcePosition,p.current=t.targetPosition,a.getState().updateNodeInternals(new Map([[t.id,{id:t.id,nodeElement:u.current,force:!0}]])))}},[t.id,r,t.sourcePosition,t.targetPosition]),u}function bS({id:t,onClick:r,onMouseEnter:o,onMouseMove:s,onMouseLeave:a,onContextMenu:u,onDoubleClick:c,nodesDraggable:h,elementsSelectable:p,nodesConnectable:y,nodesFocusable:x,resizeObserver:v,noDragClassName:g,noPanClassName:_,disableKeyboardA11y:S,rfId:N,nodeTypes:b,nodeClickDistance:E,onError:I}){const{node:w,internals:j,isParent:A}=De(Z=>{const se=Z.nodeLookup.get(t),me=Z.parentLookup.has(t);return{node:se,internals:se.internals,isParent:me}},Qe);let $=w.type||"default",F=(b==null?void 0:b[$])||lp[$];F===void 0&&(I==null||I("003",wn.error003($)),$="default",F=(b==null?void 0:b.default)||lp.default);const Y=!!(w.draggable||h&&typeof w.draggable>"u"),q=!!(w.selectable||p&&typeof w.selectable>"u"),re=!!(w.connectable||y&&typeof w.connectable>"u"),J=!!(w.focusable||x&&typeof w.focusable>"u"),te=Ge(),Q=wg(w),C=jS({node:w,nodeType:$,hasDimensions:Q,resizeObserver:v}),V=qg({nodeRef:C,disabled:w.hidden||!Y,noDragClassName:g,handleSelector:w.dragHandle,nodeId:t,isSelectable:q,nodeClickDistance:E}),W=Kg();if(w.hidden)return null;const U=Sn(w),M=mS(w),D=q||Y||r||o||s||a,H=o?Z=>o(Z,{...j.userNode}):void 0,R=s?Z=>s(Z,{...j.userNode}):void 0,z=a?Z=>a(Z,{...j.userNode}):void 0,ne=u?Z=>u(Z,{...j.userNode}):void 0,oe=c?Z=>c(Z,{...j.userNode}):void 0,fe=Z=>{const{selectNodesOnDrag:se,nodeDragThreshold:me}=te.getState();q&&(!se||!Y||me>0)&&vc({id:t,store:te,nodeRef:C}),r&&r(Z,{...j.userNode})},he=Z=>{if(!(kg(Z.nativeEvent)||S)){if(cg.includes(Z.key)&&q){const se=Z.key==="Escape";vc({id:t,store:te,unselect:se,nodeRef:C})}else if(Y&&w.selected&&Object.prototype.hasOwnProperty.call(Xa,Z.key)){Z.preventDefault();const{ariaLabelConfig:se}=te.getState();te.setState({ariaLiveMessage:se["node.a11yDescription.ariaLiveMessage"]({direction:Z.key.replace("Arrow","").toLowerCase(),x:~~j.positionAbsolute.x,y:~~j.positionAbsolute.y})}),W({direction:Xa[Z.key],factor:Z.shiftKey?4:1})}}},pe=()=>{var Pe;if(S||!((Pe=C.current)!=null&&Pe.matches(":focus-visible")))return;const{transform:Z,width:se,height:me,autoPanOnNodeFocus:Ne,setCenter:we}=te.getState();if(!Ne)return;Cc(new Map([[t,w]]),{x:0,y:0,width:se,height:me},Z,!0).length>0||we(w.position.x+U.width/2,w.position.y+U.height/2,{zoom:Z[2]})};return d.jsx("div",{className:ot(["react-flow__node",`react-flow__node-${$}`,{[_]:Y},w.className,{selected:w.selected,selectable:q,parent:A,draggable:Y,dragging:V}]),ref:C,style:{zIndex:j.z,transform:`translate(${j.positionAbsolute.x}px,${j.positionAbsolute.y}px)`,pointerEvents:D?"all":"none",visibility:Q?"visible":"hidden",...w.style,...M},"data-id":t,"data-testid":`rf__node-${t}`,onMouseEnter:H,onMouseMove:R,onMouseLeave:z,onContextMenu:ne,onClick:fe,onDoubleClick:oe,onKeyDown:J?he:void 0,tabIndex:J?0:void 0,onFocus:J?pe:void 0,role:w.ariaRole??(J?"group":void 0),"aria-roledescription":"node","aria-describedby":S?void 0:`${Bg}-${N}`,"aria-label":w.ariaLabel,...w.domAttributes,children:d.jsx(iS,{value:t,children:d.jsx(F,{id:t,data:w.data,type:$,positionAbsoluteX:j.positionAbsolute.x,positionAbsoluteY:j.positionAbsolute.y,selected:w.selected??!1,selectable:q,draggable:Y,deletable:w.deletable??!0,isConnectable:re,sourcePosition:w.sourcePosition,targetPosition:w.targetPosition,dragging:V,dragHandle:w.dragHandle,zIndex:j.z,parentId:w.parentId,...U})})})}var ES=L.memo(bS);const CS=t=>({nodesConnectable:t.nodesConnectable,nodesFocusable:t.nodesFocusable,elementsSelectable:t.elementsSelectable,onError:t.onError});function em(t){const{nodesConnectable:r,nodesFocusable:o,elementsSelectable:s,onError:a}=De(CS,Qe),u=SS(t.onlyRenderVisibleElements),c=NS();return d.jsx("div",{className:"react-flow__nodes",style:ul,children:u.map(h=>d.jsx(ES,{id:h,nodeTypes:t.nodeTypes,nodeExtent:t.nodeExtent,onClick:t.onNodeClick,onMouseEnter:t.onNodeMouseEnter,onMouseMove:t.onNodeMouseMove,onMouseLeave:t.onNodeMouseLeave,onContextMenu:t.onNodeContextMenu,onDoubleClick:t.onNodeDoubleClick,noDragClassName:t.noDragClassName,noPanClassName:t.noPanClassName,rfId:t.rfId,disableKeyboardA11y:t.disableKeyboardA11y,resizeObserver:c,nodesDraggable:t.nodesDraggable??!0,nodesConnectable:r,nodesFocusable:o,elementsSelectable:s,nodeClickDistance:t.nodeClickDistance,onError:a},h))})}em.displayName="NodeRenderer";const MS=L.memo(em);function PS(t){return De(L.useCallback(o=>{if(!t)return o.edges.map(a=>a.id);const s=[];if(o.width&&o.height)for(const a of o.edges){const u=o.nodeLookup.get(a.source),c=o.nodeLookup.get(a.target);u&&c&&k1({sourceNode:u,targetNode:c,width:o.width,height:o.height,transform:o.transform})&&s.push(a.id)}return s},[t]),Qe)}const IS=({color:t="none",strokeWidth:r=1})=>{const o={strokeWidth:r,...t&&{stroke:t}};return d.jsx("polyline",{className:"arrow",style:o,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},RS=({color:t="none",strokeWidth:r=1})=>{const o={strokeWidth:r,...t&&{stroke:t,fill:t}};return d.jsx("polyline",{className:"arrowclosed",style:o,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},cp={[us.Arrow]:IS,[us.ArrowClosed]:RS};function TS(t){const r=Ge();return L.useMemo(()=>{var a,u;return Object.prototype.hasOwnProperty.call(cp,t)?cp[t]:((u=(a=r.getState()).onError)==null||u.call(a,"009",wn.error009(t)),null)},[t])}const LS=({id:t,type:r,color:o,width:s=12.5,height:a=12.5,markerUnits:u="strokeWidth",strokeWidth:c,orient:h="auto-start-reverse"})=>{const p=TS(r);return p?d.jsx("marker",{className:"react-flow__arrowhead",id:t,markerWidth:`${s}`,markerHeight:`${a}`,viewBox:"-10 -10 20 20",markerUnits:u,orient:h,refX:"0",refY:"0",children:d.jsx(p,{color:o,strokeWidth:c})}):null},tm=({defaultColor:t,rfId:r})=>{const o=De(u=>u.edges),s=De(u=>u.defaultEdgeOptions),a=L.useMemo(()=>I1(o,{id:r,defaultColor:t,defaultMarkerStart:s==null?void 0:s.markerStart,defaultMarkerEnd:s==null?void 0:s.markerEnd}),[o,s,r,t]);return a.length?d.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:d.jsx("defs",{children:a.map(u=>d.jsx(LS,{id:u.id,type:u.type,color:u.color,width:u.width,height:u.height,markerUnits:u.markerUnits,strokeWidth:u.strokeWidth,orient:u.orient},u.id))})}):null};tm.displayName="MarkerDefinitions";var AS=L.memo(tm);function nm({x:t,y:r,label:o,labelStyle:s,labelShowBg:a=!0,labelBgStyle:u,labelBgPadding:c=[2,4],labelBgBorderRadius:h=2,children:p,className:y,...x}){const[v,g]=L.useState({x:1,y:0,width:0,height:0}),_=ot(["react-flow__edge-textwrapper",y]),S=L.useRef(null);return L.useEffect(()=>{if(S.current){const N=S.current.getBBox();g({x:N.x,y:N.y,width:N.width,height:N.height})}},[o]),o?d.jsxs("g",{transform:`translate(${t-v.width/2} ${r-v.height/2})`,className:_,visibility:v.width?"visible":"hidden",...x,children:[a&&d.jsx("rect",{width:v.width+2*c[0],x:-c[0],y:-c[1],height:v.height+2*c[1],className:"react-flow__edge-textbg",style:u,rx:h,ry:h}),d.jsx("text",{className:"react-flow__edge-text",y:v.height/2,dy:"0.3em",ref:S,style:s,children:o}),p]}):null}nm.displayName="EdgeText";const $S=L.memo(nm);function ws({path:t,labelX:r,labelY:o,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:h,labelBgBorderRadius:p,interactionWidth:y=20,...x}){return d.jsxs(d.Fragment,{children:[d.jsx("path",{...x,d:t,fill:"none",className:ot(["react-flow__edge-path",x.className])}),y?d.jsx("path",{d:t,fill:"none",strokeOpacity:0,strokeWidth:y,className:"react-flow__edge-interaction"}):null,s&&vn(r)&&vn(o)?d.jsx($S,{x:r,y:o,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:h,labelBgBorderRadius:p}):null]})}function dp({pos:t,x1:r,y1:o,x2:s,y2:a}){return t===ke.Left||t===ke.Right?[.5*(r+s),o]:[r,.5*(o+a)]}function rm({sourceX:t,sourceY:r,sourcePosition:o=ke.Bottom,targetX:s,targetY:a,targetPosition:u=ke.Top}){const[c,h]=dp({pos:o,x1:t,y1:r,x2:s,y2:a}),[p,y]=dp({pos:u,x1:s,y1:a,x2:t,y2:r}),[x,v,g,_]=jg({sourceX:t,sourceY:r,targetX:s,targetY:a,sourceControlX:c,sourceControlY:h,targetControlX:p,targetControlY:y});return[`M${t},${r} C${c},${h} ${p},${y} ${s},${a}`,x,v,g,_]}function om(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,sourcePosition:c,targetPosition:h,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:E})=>{const[I,w,j]=rm({sourceX:o,sourceY:s,sourcePosition:c,targetX:a,targetY:u,targetPosition:h}),A=t.isInternal?void 0:r;return d.jsx(ws,{id:A,path:I,labelX:w,labelY:j,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:E})})}const zS=om({isInternal:!1}),im=om({isInternal:!0});zS.displayName="SimpleBezierEdge";im.displayName="SimpleBezierEdgeInternal";function sm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,sourcePosition:_=ke.Bottom,targetPosition:S=ke.Top,markerEnd:N,markerStart:b,pathOptions:E,interactionWidth:I})=>{const[w,j,A]=Ya({sourceX:o,sourceY:s,sourcePosition:_,targetX:a,targetY:u,targetPosition:S,borderRadius:E==null?void 0:E.borderRadius,offset:E==null?void 0:E.offset,stepPosition:E==null?void 0:E.stepPosition}),$=t.isInternal?void 0:r;return d.jsx(ws,{id:$,path:w,labelX:j,labelY:A,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:N,markerStart:b,interactionWidth:I})})}const am=sm({isInternal:!1}),lm=sm({isInternal:!0});am.displayName="SmoothStepEdge";lm.displayName="SmoothStepEdgeInternal";function um(t){return L.memo(({id:r,...o})=>{var a;const s=t.isInternal?void 0:r;return d.jsx(am,{...o,id:s,pathOptions:L.useMemo(()=>{var u;return{borderRadius:0,offset:(u=o.pathOptions)==null?void 0:u.offset}},[(a=o.pathOptions)==null?void 0:a.offset])})})}const DS=um({isInternal:!1}),cm=um({isInternal:!0});DS.displayName="StepEdge";cm.displayName="StepEdgeInternal";function dm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:_,markerStart:S,interactionWidth:N})=>{const[b,E,I]=Cg({sourceX:o,sourceY:s,targetX:a,targetY:u}),w=t.isInternal?void 0:r;return d.jsx(ws,{id:w,path:b,labelX:E,labelY:I,label:c,labelStyle:h,labelShowBg:p,labelBgStyle:y,labelBgPadding:x,labelBgBorderRadius:v,style:g,markerEnd:_,markerStart:S,interactionWidth:N})})}const OS=dm({isInternal:!1}),fm=dm({isInternal:!0});OS.displayName="StraightEdge";fm.displayName="StraightEdgeInternal";function hm(t){return L.memo(({id:r,sourceX:o,sourceY:s,targetX:a,targetY:u,sourcePosition:c=ke.Bottom,targetPosition:h=ke.Top,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,pathOptions:E,interactionWidth:I})=>{const[w,j,A]=bg({sourceX:o,sourceY:s,sourcePosition:c,targetX:a,targetY:u,targetPosition:h,curvature:E==null?void 0:E.curvature}),$=t.isInternal?void 0:r;return d.jsx(ws,{id:$,path:w,labelX:j,labelY:A,label:p,labelStyle:y,labelShowBg:x,labelBgStyle:v,labelBgPadding:g,labelBgBorderRadius:_,style:S,markerEnd:N,markerStart:b,interactionWidth:I})})}const FS=hm({isInternal:!1}),pm=hm({isInternal:!0});FS.displayName="BezierEdge";pm.displayName="BezierEdgeInternal";const fp={default:pm,straight:fm,step:cm,smoothstep:lm,simplebezier:im},hp={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null,zIndex:void 0},HS=(t,r,o)=>o===ke.Left?t-r:o===ke.Right?t+r:t,BS=(t,r,o)=>o===ke.Top?t-r:o===ke.Bottom?t+r:t,pp="react-flow__edgeupdater";function gp({position:t,centerX:r,centerY:o,radius:s=10,onMouseDown:a,onMouseEnter:u,onMouseOut:c,type:h}){return d.jsx("circle",{onMouseDown:a,onMouseEnter:u,onMouseOut:c,className:ot([pp,`${pp}-${h}`]),cx:HS(r,s,t),cy:BS(o,s,t),r:s,stroke:"transparent",fill:"transparent"})}function VS({isReconnectable:t,reconnectRadius:r,edge:o,sourceX:s,sourceY:a,targetX:u,targetY:c,sourcePosition:h,targetPosition:p,onReconnect:y,onReconnectStart:x,onReconnectEnd:v,setReconnecting:g,setUpdateHover:_}){const S=Ge(),N=(j,A)=>{if(j.button!==0)return;const{autoPanOnConnect:$,domNode:F,connectionMode:Y,connectionRadius:q,lib:re,onConnectStart:J,cancelConnection:te,nodeLookup:Q,rfId:C,panBy:V,updateConnection:W}=S.getState(),U=A.type==="target",M=(R,z)=>{g(!1),v==null||v(R,o,A.type,z)},D=R=>y==null?void 0:y(o,R),H=(R,z)=>{g(!0),x==null||x(j,o,A.type),J==null||J(R,z)};yc.onPointerDown(j.nativeEvent,{autoPanOnConnect:$,connectionMode:Y,connectionRadius:q,domNode:F,handleId:A.id,nodeId:A.nodeId,nodeLookup:Q,isTarget:U,edgeUpdaterType:A.type,lib:re,flowId:C,cancelConnection:te,panBy:V,isValidConnection:(...R)=>{var z,ne;return((ne=(z=S.getState()).isValidConnection)==null?void 0:ne.call(z,...R))??!0},onConnect:D,onConnectStart:H,onConnectEnd:(...R)=>{var z,ne;return(ne=(z=S.getState()).onConnectEnd)==null?void 0:ne.call(z,...R)},onReconnectEnd:M,updateConnection:W,getTransform:()=>S.getState().transform,getFromHandle:()=>S.getState().connection.fromHandle,dragThreshold:S.getState().connectionDragThreshold,handleDomNode:j.currentTarget})},b=j=>N(j,{nodeId:o.target,id:o.targetHandle??null,type:"target"}),E=j=>N(j,{nodeId:o.source,id:o.sourceHandle??null,type:"source"}),I=()=>_(!0),w=()=>_(!1);return d.jsxs(d.Fragment,{children:[(t===!0||t==="source")&&d.jsx(gp,{position:h,centerX:s,centerY:a,radius:r,onMouseDown:b,onMouseEnter:I,onMouseOut:w,type:"source"}),(t===!0||t==="target")&&d.jsx(gp,{position:p,centerX:u,centerY:c,radius:r,onMouseDown:E,onMouseEnter:I,onMouseOut:w,type:"target"})]})}function WS({id:t,edgesFocusable:r,edgesReconnectable:o,elementsSelectable:s,onClick:a,onDoubleClick:u,onContextMenu:c,onMouseEnter:h,onMouseMove:p,onMouseLeave:y,reconnectRadius:x,onReconnect:v,onReconnectStart:g,onReconnectEnd:_,rfId:S,edgeTypes:N,noPanClassName:b,onError:E,disableKeyboardA11y:I}){let w=De(we=>we.edgeLookup.get(t));const j=De(we=>we.defaultEdgeOptions);w=j?{...j,...w}:w;let A=w.type||"default",$=(N==null?void 0:N[A])||fp[A];$===void 0&&(E==null||E("011",wn.error011(A)),A="default",$=(N==null?void 0:N.default)||fp.default);const F=!!(w.focusable||r&&typeof w.focusable>"u"),Y=typeof v<"u"&&(w.reconnectable||o&&typeof w.reconnectable>"u"),q=!!(w.selectable||s&&typeof w.selectable>"u"),re=L.useRef(null),[J,te]=L.useState(!1),[Q,C]=L.useState(!1),V=Ge(),{zIndex:W=w.zIndex,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z}=De(L.useCallback(we=>{const ve=we.nodeLookup.get(w.source),Pe=we.nodeLookup.get(w.target);if(!ve||!Pe)return hp;const ue=P1({id:t,sourceNode:ve,targetNode:Pe,sourceHandle:w.sourceHandle||null,targetHandle:w.targetHandle||null,connectionMode:we.connectionMode,onError:E}),je=S1({selected:w.selected,zIndex:w.zIndex,sourceNode:ve,targetNode:Pe,elevateOnSelect:we.elevateEdgesOnSelect,zIndexMode:we.zIndexMode});return{...ue||hp,zIndex:je}},[w.source,w.target,w.sourceHandle,w.targetHandle,w.selected,w.zIndex,E]),Qe),ne=L.useMemo(()=>w.markerStart?`url('#${gc(w.markerStart,S)}')`:void 0,[w.markerStart,S]),oe=L.useMemo(()=>w.markerEnd?`url('#${gc(w.markerEnd,S)}')`:void 0,[w.markerEnd,S]);if(w.hidden||U===null||M===null||D===null||H===null)return null;const fe=we=>{var je;const{addSelectedEdges:ve,unselectNodesAndEdges:Pe,multiSelectionActive:ue}=V.getState();q&&(V.setState({nodesSelectionActive:!1}),w.selected&&ue?(Pe({nodes:[],edges:[w]}),(je=re.current)==null||je.blur()):ve([t])),a&&a(we,w)},he=u?we=>{u(we,{...w})}:void 0,pe=c?we=>{c(we,{...w})}:void 0,Z=h?we=>{h(we,{...w})}:void 0,se=p?we=>{p(we,{...w})}:void 0,me=y?we=>{y(we,{...w})}:void 0,Ne=we=>{var ve;if(!I&&cg.includes(we.key)&&q){const{unselectNodesAndEdges:Pe,addSelectedEdges:ue}=V.getState();we.key==="Escape"?((ve=re.current)==null||ve.blur(),Pe({edges:[w]})):ue([t])}};return d.jsx("svg",{style:{zIndex:W},children:d.jsxs("g",{className:ot(["react-flow__edge",`react-flow__edge-${A}`,w.className,b,{selected:w.selected,animated:w.animated,inactive:!q&&!a,updating:J,selectable:q}]),onClick:fe,onDoubleClick:he,onContextMenu:pe,onMouseEnter:Z,onMouseMove:se,onMouseLeave:me,onKeyDown:F?Ne:void 0,tabIndex:F?0:void 0,role:w.ariaRole??(F?"group":"img"),"aria-roledescription":"edge","data-id":t,"data-testid":`rf__edge-${t}`,"aria-label":w.ariaLabel===null?void 0:w.ariaLabel||`Edge from ${w.source} to ${w.target}`,"aria-describedby":F?`${Vg}-${S}`:void 0,ref:re,...w.domAttributes,children:[!Q&&d.jsx($,{id:t,source:w.source,target:w.target,type:w.type,selected:w.selected,animated:w.animated,selectable:q,deletable:w.deletable??!0,label:w.label,labelStyle:w.labelStyle,labelShowBg:w.labelShowBg,labelBgStyle:w.labelBgStyle,labelBgPadding:w.labelBgPadding,labelBgBorderRadius:w.labelBgBorderRadius,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z,data:w.data,style:w.style,sourceHandleId:w.sourceHandle,targetHandleId:w.targetHandle,markerStart:ne,markerEnd:oe,pathOptions:"pathOptions"in w?w.pathOptions:void 0,interactionWidth:w.interactionWidth}),Y&&d.jsx(VS,{edge:w,isReconnectable:Y,reconnectRadius:x,onReconnect:v,onReconnectStart:g,onReconnectEnd:_,sourceX:U,sourceY:M,targetX:D,targetY:H,sourcePosition:R,targetPosition:z,setUpdateHover:te,setReconnecting:C})]})})}var US=L.memo(WS);const GS=t=>({edgesFocusable:t.edgesFocusable,edgesReconnectable:t.edgesReconnectable,elementsSelectable:t.elementsSelectable,connectionMode:t.connectionMode,onError:t.onError});function gm({defaultMarkerColor:t,onlyRenderVisibleElements:r,rfId:o,edgeTypes:s,noPanClassName:a,onReconnect:u,onEdgeContextMenu:c,onEdgeMouseEnter:h,onEdgeMouseMove:p,onEdgeMouseLeave:y,onEdgeClick:x,reconnectRadius:v,onEdgeDoubleClick:g,onReconnectStart:_,onReconnectEnd:S,disableKeyboardA11y:N}){const{edgesFocusable:b,edgesReconnectable:E,elementsSelectable:I,onError:w}=De(GS,Qe),j=PS(r);return d.jsxs("div",{className:"react-flow__edges",children:[d.jsx(AS,{defaultColor:t,rfId:o}),j.map(A=>d.jsx(US,{id:A,edgesFocusable:b,edgesReconnectable:E,elementsSelectable:I,noPanClassName:a,onReconnect:u,onContextMenu:c,onMouseEnter:h,onMouseMove:p,onMouseLeave:y,onClick:x,reconnectRadius:v,onDoubleClick:g,onReconnectStart:_,onReconnectEnd:S,rfId:o,onError:w,edgeTypes:s,disableKeyboardA11y:N},A))]})}gm.displayName="EdgeRenderer";const YS=L.memo(gm),mp=t=>`translate(${t[0]}px,${t[1]}px) scale(${t[2]})`;function XS({children:t}){const r=Ge(),o=L.useRef(null),[s]=L.useState(()=>r.getState().transform);return Yg(()=>{let a=null;const u=()=>{const c=r.getState().transform;a&&c[0]===a[0]&&c[1]===a[1]&&c[2]===a[2]||(a=c,o.current&&(o.current.style.transform=mp(c)))};return u(),r.subscribe(u)},[r]),d.jsx("div",{ref:o,className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:mp(s)},children:t})}function qS(t){const r=ll(),o=L.useRef(!1);L.useEffect(()=>{!o.current&&r.viewportInitialized&&t&&(setTimeout(()=>t(r),1),o.current=!0)},[t,r.viewportInitialized])}const KS=t=>{var r;return(r=t.panZoom)==null?void 0:r.syncViewport};function QS(t){const r=De(KS),o=Ge();return L.useEffect(()=>{t&&(r==null||r(t),o.setState({transform:[t.x,t.y,t.zoom]}))},[t,r]),null}function ZS(t){return t.connection.inProgress?{...t.connection,to:xs(t.connection.to,t.transform)}:{...t.connection}}function JS(t){return ZS}function ek(t){const r=JS();return De(r,Qe)}const tk=t=>({nodesConnectable:t.nodesConnectable,isValid:t.connection.isValid,inProgress:t.connection.inProgress,width:t.width,height:t.height});function nk({containerStyle:t,style:r,type:o,component:s}){const{nodesConnectable:a,width:u,height:c,isValid:h,inProgress:p}=De(tk,Qe);return!(u&&a&&p)?null:d.jsx("svg",{style:t,width:u,height:c,className:"react-flow__connectionline react-flow__container",children:d.jsx("g",{className:ot(["react-flow__connection",hg(h)]),children:d.jsx(mm,{style:r,type:o,CustomComponent:s,isValid:h})})})}const mm=({style:t,type:r=$r.Bezier,CustomComponent:o,isValid:s})=>{const{inProgress:a,from:u,fromNode:c,fromHandle:h,fromPosition:p,to:y,toNode:x,toHandle:v,toPosition:g,pointer:_}=ek();if(!a)return;if(o)return d.jsx(o,{connectionLineType:r,connectionLineStyle:t,fromNode:c,fromHandle:h,fromX:u.x,fromY:u.y,toX:y.x,toY:y.y,fromPosition:p,toPosition:g,connectionStatus:hg(s),toNode:x,toHandle:v,pointer:_});let S="";const N={sourceX:u.x,sourceY:u.y,sourcePosition:p,targetX:y.x,targetY:y.y,targetPosition:g};switch(r){case $r.Bezier:[S]=bg(N);break;case $r.SimpleBezier:[S]=rm(N);break;case $r.Step:[S]=Ya({...N,borderRadius:0});break;case $r.SmoothStep:[S]=Ya(N);break;default:[S]=Cg(N)}return d.jsx("path",{d:S,fill:"none",className:"react-flow__connection-path",style:t})};mm.displayName="ConnectionLine";const rk={};function yp(t=rk){L.useRef(t),Ge(),L.useEffect(()=>{},[t])}function ok(){Ge(),L.useRef(!1),L.useEffect(()=>{},[])}function ym({nodeTypes:t,edgeTypes:r,onInit:o,onNodeClick:s,onEdgeClick:a,onNodeDoubleClick:u,onEdgeDoubleClick:c,onNodeMouseEnter:h,onNodeMouseMove:p,onNodeMouseLeave:y,onNodeContextMenu:x,onSelectionContextMenu:v,onSelectionStart:g,onSelectionEnd:_,connectionLineType:S,connectionLineStyle:N,connectionLineComponent:b,connectionLineContainerStyle:E,selectionKeyCode:I,selectionOnDrag:w,selectionMode:j,multiSelectionKeyCode:A,panActivationKeyCode:$,zoomActivationKeyCode:F,deleteKeyCode:Y,onlyRenderVisibleElements:q,elementsSelectable:re,defaultViewport:J,translateExtent:te,minZoom:Q,maxZoom:C,preventScrolling:V,defaultMarkerColor:W,zoomOnScroll:U,zoomOnPinch:M,panOnScroll:D,panOnScrollSpeed:H,panOnScrollMode:R,zoomOnDoubleClick:z,panOnDrag:ne,autoPanOnSelection:oe,onPaneClick:fe,onPaneMouseEnter:he,onPaneMouseMove:pe,onPaneMouseLeave:Z,onPaneScroll:se,onPaneContextMenu:me,paneClickDistance:Ne,nodeClickDistance:we,onEdgeContextMenu:ve,onEdgeMouseEnter:Pe,onEdgeMouseMove:ue,onEdgeMouseLeave:je,reconnectRadius:Le,onReconnect:nt,onReconnectStart:lt,onReconnectEnd:ut,noDragClassName:Ye,noWheelClassName:wt,noPanClassName:Yt,disableKeyboardA11y:gt,nodeExtent:mt,rfId:Ct,viewport:ct,onViewportChange:et,nodesDraggable:On}){return yp(t),yp(r),ok(),qS(o),QS(ct),d.jsx(wS,{onPaneClick:fe,onPaneMouseEnter:he,onPaneMouseMove:pe,onPaneMouseLeave:Z,onPaneContextMenu:me,onPaneScroll:se,paneClickDistance:Ne,deleteKeyCode:Y,selectionKeyCode:I,selectionOnDrag:w,selectionMode:j,onSelectionStart:g,onSelectionEnd:_,multiSelectionKeyCode:A,panActivationKeyCode:$,zoomActivationKeyCode:F,elementsSelectable:re,zoomOnScroll:U,zoomOnPinch:M,zoomOnDoubleClick:z,panOnScroll:D,panOnScrollSpeed:H,panOnScrollMode:R,panOnDrag:ne,autoPanOnSelection:oe,defaultViewport:J,translateExtent:te,minZoom:Q,maxZoom:C,onSelectionContextMenu:v,preventScrolling:V,noDragClassName:Ye,noWheelClassName:wt,noPanClassName:Yt,disableKeyboardA11y:gt,onViewportChange:et,isControlledViewport:!!ct,children:d.jsxs(XS,{children:[d.jsx(YS,{edgeTypes:r,onEdgeClick:a,onEdgeDoubleClick:c,onReconnect:nt,onReconnectStart:lt,onReconnectEnd:ut,onlyRenderVisibleElements:q,onEdgeContextMenu:ve,onEdgeMouseEnter:Pe,onEdgeMouseMove:ue,onEdgeMouseLeave:je,reconnectRadius:Le,defaultMarkerColor:W,noPanClassName:Yt,disableKeyboardA11y:gt,rfId:Ct}),d.jsx(nk,{style:N,type:S,component:b,containerStyle:E}),d.jsx("div",{className:"react-flow__edgelabel-renderer"}),d.jsx(MS,{nodeTypes:t,onNodeClick:s,onNodeDoubleClick:u,onNodeMouseEnter:h,onNodeMouseMove:p,onNodeMouseLeave:y,onNodeContextMenu:x,nodeClickDistance:we,onlyRenderVisibleElements:q,noPanClassName:Yt,noDragClassName:Ye,disableKeyboardA11y:gt,nodeExtent:mt,rfId:Ct,nodesDraggable:On}),d.jsx("div",{className:"react-flow__viewport-portal"})]})})}ym.displayName="GraphView";const ik=L.memo(ym),sk=xg(),vp=({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p=.5,maxZoom:y=2,nodeOrigin:x,nodeExtent:v,zIndexMode:g="basic"}={})=>{const _=new Map,S=new Map,N=new Map,b=new Map,E=s??r??[],I=o??t??[],w=x??[0,0],j=v??as;Ig(N,b,E);const{nodesInitialized:A}=mc(I,_,S,{nodeOrigin:w,nodeExtent:j,zIndexMode:g});let $=[0,0,1];if(c&&a&&u){const F=ys(_,{filter:J=>!!((J.width||J.initialWidth)&&(J.height||J.initialHeight))}),{x:Y,y:q,zoom:re}=Pc(F,a,u,p,y,(h==null?void 0:h.padding)??.1);$=[Y,q,re]}return{rfId:"1",width:a??0,height:u??0,transform:$,nodes:I,nodesInitialized:A,nodeLookup:_,parentLookup:S,edges:E,edgeLookup:b,connectionLookup:N,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:o!==void 0,hasDefaultEdges:s!==void 0,panZoom:null,minZoom:p,maxZoom:y,translateExtent:as,nodeExtent:j,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:ti.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:w,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:c??!1,fitViewOptions:h,fitViewResolver:null,connection:{...fg},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:sk,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:dg,zIndexMode:g,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},ak=({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p,maxZoom:y,nodeOrigin:x,nodeExtent:v,zIndexMode:g})=>x_((_,S)=>{async function N(){const{nodeLookup:b,panZoom:E,fitViewOptions:I,fitViewResolver:w,width:j,height:A,minZoom:$,maxZoom:F}=S();E&&(await g1({nodes:b,width:j,height:A,panZoom:E,minZoom:$,maxZoom:F},I),w==null||w.resolve(!0),_({fitViewResolver:null}))}return{...vp({nodes:t,edges:r,width:a,height:u,fitView:c,fitViewOptions:h,minZoom:p,maxZoom:y,nodeOrigin:x,nodeExtent:v,defaultNodes:o,defaultEdges:s,zIndexMode:g}),setNodes:b=>{const{nodeLookup:E,parentLookup:I,nodeOrigin:w,nodeExtent:j,elevateNodesOnSelect:A,fitViewQueued:$,zIndexMode:F,nodesSelectionActive:Y}=S(),{nodesInitialized:q,hasSelectedNodes:re}=mc(b,E,I,{nodeOrigin:w,nodeExtent:j,elevateNodesOnSelect:A,checkEquality:!0,zIndexMode:F}),J=Y&&re;$&&q?(N(),_({nodes:b,nodesInitialized:q,fitViewQueued:!1,fitViewOptions:void 0,nodesSelectionActive:J})):_({nodes:b,nodesInitialized:q,nodesSelectionActive:J})},setEdges:b=>{const{connectionLookup:E,edgeLookup:I}=S();Ig(E,I,b),_({edges:b})},setDefaultNodesAndEdges:(b,E)=>{if(b){const{setNodes:I}=S();I(b),_({hasDefaultNodes:!0})}if(E){const{setEdges:I}=S();I(E),_({hasDefaultEdges:!0})}},updateNodeInternals:b=>{const{triggerNodeChanges:E,nodeLookup:I,parentLookup:w,domNode:j,nodeOrigin:A,nodeExtent:$,debug:F,fitViewQueued:Y,zIndexMode:q}=S(),{changes:re,updatedInternals:J}=D1(b,I,w,j,A,$,q);J&&(L1(I,w,{nodeOrigin:A,nodeExtent:$,zIndexMode:q}),Y?(N(),_({fitViewQueued:!1,fitViewOptions:void 0})):_({}),(re==null?void 0:re.length)>0&&(F&&console.log("React Flow: trigger node changes",re),E==null||E(re)))},updateNodePositions:(b,E=!1)=>{const I=[];let w=[];const{nodeLookup:j,triggerNodeChanges:A,connection:$,updateConnection:F,onNodesChangeMiddlewareMap:Y}=S();for(const[q,re]of b){const J=j.get(q),te=!!(J!=null&&J.expandParent&&(J!=null&&J.parentId)&&(re!=null&&re.position)),Q={id:q,type:"position",position:te?{x:Math.max(0,re.position.x),y:Math.max(0,re.position.y)}:re.position,dragging:E};if(J&&$.inProgress&&$.fromNode.id===J.id){const C=mo(J,$.fromHandle,ke.Left,!0);F({...$,from:C})}te&&J.parentId&&I.push({id:q,parentId:J.parentId,rect:{...re.internals.positionAbsolute,width:re.measured.width??0,height:re.measured.height??0}}),w.push(Q)}if(I.length>0){const{parentLookup:q,nodeOrigin:re}=S(),J=$c(I,j,q,re);w.push(...J)}for(const q of Y.values())w=q(w);A(w)},triggerNodeChanges:b=>{const{onNodesChange:E,setNodes:I,nodes:w,hasDefaultNodes:j,debug:A}=S();if(b!=null&&b.length){if(j){const $=F_(b,w);I($)}A&&console.log("React Flow: trigger node changes",b),E==null||E(b)}},triggerEdgeChanges:b=>{const{onEdgesChange:E,setEdges:I,edges:w,hasDefaultEdges:j,debug:A}=S();if(b!=null&&b.length){if(j){const $=H_(b,w);I($)}A&&console.log("React Flow: trigger edge changes",b),E==null||E(b)}},addSelectedNodes:b=>{const{multiSelectionActive:E,edgeLookup:I,nodeLookup:w,triggerNodeChanges:j,triggerEdgeChanges:A}=S();if(E){const $=b.map(F=>ao(F,!0));j($);return}j(Ko(w,new Set([...b]),!0)),A(Ko(I))},addSelectedEdges:b=>{const{multiSelectionActive:E,edgeLookup:I,nodeLookup:w,triggerNodeChanges:j,triggerEdgeChanges:A}=S();if(E){const $=b.map(F=>ao(F,!0));A($);return}A(Ko(I,new Set([...b]))),j(Ko(w,new Set,!0))},unselectNodesAndEdges:({nodes:b,edges:E}={})=>{const{edges:I,nodes:w,nodeLookup:j,triggerNodeChanges:A,triggerEdgeChanges:$}=S(),F=b||w,Y=E||I,q=[];for(const J of F){if(!J.selected)continue;const te=j.get(J.id);te&&(te.selected=!1),q.push(ao(J.id,!1))}const re=[];for(const J of Y)J.selected&&re.push(ao(J.id,!1));A(q),$(re)},setMinZoom:b=>{const{panZoom:E,maxZoom:I}=S();E==null||E.setScaleExtent([b,I]),_({minZoom:b})},setMaxZoom:b=>{const{panZoom:E,minZoom:I}=S();E==null||E.setScaleExtent([I,b]),_({maxZoom:b})},setTranslateExtent:b=>{var E;(E=S().panZoom)==null||E.setTranslateExtent(b),_({translateExtent:b})},resetSelectedElements:()=>{const{edges:b,nodes:E,triggerNodeChanges:I,triggerEdgeChanges:w,elementsSelectable:j}=S();if(!j)return;const A=E.reduce((F,Y)=>Y.selected?[...F,ao(Y.id,!1)]:F,[]),$=b.reduce((F,Y)=>Y.selected?[...F,ao(Y.id,!1)]:F,[]);I(A),w($)},setNodeExtent:b=>{const{nodes:E,nodeLookup:I,parentLookup:w,nodeOrigin:j,elevateNodesOnSelect:A,nodeExtent:$,zIndexMode:F}=S();b[0][0]===$[0][0]&&b[0][1]===$[0][1]&&b[1][0]===$[1][0]&&b[1][1]===$[1][1]||(mc(E,I,w,{nodeOrigin:j,nodeExtent:b,elevateNodesOnSelect:A,checkEquality:!1,zIndexMode:F}),_({nodeExtent:b}))},panBy:b=>{const{transform:E,width:I,height:w,panZoom:j,translateExtent:A}=S();return O1({delta:b,panZoom:j,transform:E,translateExtent:A,width:I,height:w})},setCenter:async(b,E,I)=>{const{width:w,height:j,maxZoom:A,panZoom:$}=S();if(!$)return!1;const F=typeof(I==null?void 0:I.zoom)<"u"?I.zoom:A;return await $.setViewport({x:w/2-b*F,y:j/2-E*F,zoom:F},{duration:I==null?void 0:I.duration,ease:I==null?void 0:I.ease,interpolate:I==null?void 0:I.interpolate}),!0},cancelConnection:()=>{_({connection:{...fg}})},updateConnection:b=>{_({connection:b})},reset:()=>_({...vp()})}},Object.is);function vm({initialNodes:t,initialEdges:r,defaultNodes:o,defaultEdges:s,initialWidth:a,initialHeight:u,initialMinZoom:c,initialMaxZoom:h,initialFitViewOptions:p,fitView:y,nodeOrigin:x,nodeExtent:v,zIndexMode:g,children:_}){const[S]=L.useState(()=>ak({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,width:a,height:u,fitView:y,minZoom:c,maxZoom:h,fitViewOptions:p,nodeOrigin:x,nodeExtent:v,zIndexMode:g}));return d.jsx(w_,{value:S,children:d.jsx(G_,{children:d.jsx(aS,{children:_})})})}function lk({children:t,nodes:r,edges:o,defaultNodes:s,defaultEdges:a,width:u,height:c,fitView:h,fitViewOptions:p,minZoom:y,maxZoom:x,nodeOrigin:v,nodeExtent:g,zIndexMode:_}){return L.useContext(sl)?d.jsx(d.Fragment,{children:t}):d.jsx(vm,{initialNodes:r,initialEdges:o,defaultNodes:s,defaultEdges:a,initialWidth:u,initialHeight:c,fitView:h,initialFitViewOptions:p,initialMinZoom:y,initialMaxZoom:x,nodeOrigin:v,nodeExtent:g,zIndexMode:_,children:t})}const uk={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function ck({nodes:t,edges:r,defaultNodes:o,defaultEdges:s,className:a,nodeTypes:u,edgeTypes:c,onNodeClick:h,onEdgeClick:p,onInit:y,onMove:x,onMoveStart:v,onMoveEnd:g,onConnect:_,onConnectStart:S,onConnectEnd:N,onClickConnectStart:b,onClickConnectEnd:E,onNodeMouseEnter:I,onNodeMouseMove:w,onNodeMouseLeave:j,onNodeContextMenu:A,onNodeDoubleClick:$,onNodeDragStart:F,onNodeDrag:Y,onNodeDragStop:q,onNodesDelete:re,onEdgesDelete:J,onDelete:te,onSelectionChange:Q,onSelectionDragStart:C,onSelectionDrag:V,onSelectionDragStop:W,onSelectionContextMenu:U,onSelectionStart:M,onSelectionEnd:D,onBeforeDelete:H,connectionMode:R,connectionLineType:z=$r.Bezier,connectionLineStyle:ne,connectionLineComponent:oe,connectionLineContainerStyle:fe,deleteKeyCode:he="Backspace",selectionKeyCode:pe="Shift",selectionOnDrag:Z=!1,selectionMode:se=ls.Full,panActivationKeyCode:me="Space",multiSelectionKeyCode:Ne=ds()?"Meta":"Control",zoomActivationKeyCode:we=ds()?"Meta":"Control",snapToGrid:ve,snapGrid:Pe,onlyRenderVisibleElements:ue=!1,selectNodesOnDrag:je,nodesDraggable:Le,autoPanOnNodeFocus:nt,nodesConnectable:lt,nodesFocusable:ut,nodeOrigin:Ye=Wg,edgesFocusable:wt,edgesReconnectable:Yt,elementsSelectable:gt=!0,defaultViewport:mt=T_,minZoom:Ct=.5,maxZoom:ct=2,translateExtent:et=as,preventScrolling:On=!0,nodeExtent:Mt,defaultMarkerColor:kn="#b1b1b7",zoomOnScroll:ui=!0,zoomOnPinch:Fn=!0,panOnScroll:vo=!1,panOnScrollSpeed:lr=.5,panOnScrollMode:Or=co.Free,zoomOnDoubleClick:Hn=!0,panOnDrag:Fr=!0,onPaneClick:ur,onPaneMouseEnter:cr,onPaneMouseMove:Ft,onPaneMouseLeave:dt,onPaneScroll:Bn,onPaneContextMenu:Vn,paneClickDistance:Nn=1,nodeClickDistance:Wn=0,children:jn,onReconnect:it,onReconnectStart:dr,onReconnectEnd:bn,onEdgeContextMenu:Pt,onEdgeDoubleClick:nn,onEdgeMouseEnter:xo,onEdgeMouseMove:Ze,onEdgeMouseLeave:He,reconnectRadius:En=10,onNodesChange:Un,onEdgesChange:rn,noDragClassName:Hr="nodrag",noWheelClassName:on="nowheel",noPanClassName:It="nopan",fitView:Xt,fitViewOptions:Gn,connectOnClick:wo,attributionPosition:_o,proOptions:Rt,defaultEdgeOptions:Yn,elevateNodesOnSelect:Br=!0,elevateEdgesOnSelect:Xn=!1,disableKeyboardA11y:fr=!1,autoPanOnConnect:Ve,autoPanOnNodeDrag:ci,autoPanOnSelection:Vr=!0,autoPanSpeed:So,connectionRadius:hr,isValidConnection:di,onError:ko,style:Cn,id:_t,nodeDragThreshold:fi,connectionDragThreshold:yt,viewport:hi,onViewportChange:pi,width:Wr,height:Mn,colorMode:qn="light",debug:Pn,onScroll:qt,ariaLabelConfig:Ur,zIndexMode:Gr="basic",...pr},Yr){const sn=_t||"1",Kn=z_(qn),No=L.useCallback(gr=>{gr.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),qt==null||qt(gr)},[qt]);return d.jsx("div",{"data-testid":"rf__wrapper",...pr,onScroll:No,style:{...Cn,...uk},ref:Yr,className:ot(["react-flow",a,Kn]),id:_t,role:"application",children:d.jsxs(lk,{nodes:t,edges:r,width:Wr,height:Mn,fitView:Xt,fitViewOptions:Gn,minZoom:Ct,maxZoom:ct,nodeOrigin:Ye,nodeExtent:Mt,zIndexMode:Gr,children:[d.jsx($_,{nodes:t,edges:r,defaultNodes:o,defaultEdges:s,onConnect:_,onConnectStart:S,onConnectEnd:N,onClickConnectStart:b,onClickConnectEnd:E,nodesDraggable:Le,autoPanOnNodeFocus:nt,nodesConnectable:lt,nodesFocusable:ut,edgesFocusable:wt,edgesReconnectable:Yt,elementsSelectable:gt,elevateNodesOnSelect:Br,elevateEdgesOnSelect:Xn,minZoom:Ct,maxZoom:ct,nodeExtent:Mt,onNodesChange:Un,onEdgesChange:rn,snapToGrid:ve,snapGrid:Pe,connectionMode:R,translateExtent:et,connectOnClick:wo,defaultEdgeOptions:Yn,fitView:Xt,fitViewOptions:Gn,onNodesDelete:re,onEdgesDelete:J,onDelete:te,onNodeDragStart:F,onNodeDrag:Y,onNodeDragStop:q,onSelectionDrag:V,onSelectionDragStart:C,onSelectionDragStop:W,onMove:x,onMoveStart:v,onMoveEnd:g,noPanClassName:It,nodeOrigin:Ye,rfId:sn,autoPanOnConnect:Ve,autoPanOnNodeDrag:ci,autoPanSpeed:So,onError:ko,connectionRadius:hr,isValidConnection:di,selectNodesOnDrag:je,nodeDragThreshold:fi,connectionDragThreshold:yt,onBeforeDelete:H,debug:Pn,ariaLabelConfig:Ur,zIndexMode:Gr}),d.jsx(ik,{onInit:y,onNodeClick:h,onEdgeClick:p,onNodeMouseEnter:I,onNodeMouseMove:w,onNodeMouseLeave:j,onNodeContextMenu:A,onNodeDoubleClick:$,nodeTypes:u,edgeTypes:c,connectionLineType:z,connectionLineStyle:ne,connectionLineComponent:oe,connectionLineContainerStyle:fe,selectionKeyCode:pe,selectionOnDrag:Z,selectionMode:se,deleteKeyCode:he,multiSelectionKeyCode:Ne,panActivationKeyCode:me,zoomActivationKeyCode:we,onlyRenderVisibleElements:ue,defaultViewport:mt,translateExtent:et,minZoom:Ct,maxZoom:ct,preventScrolling:On,zoomOnScroll:ui,zoomOnPinch:Fn,zoomOnDoubleClick:Hn,panOnScroll:vo,panOnScrollSpeed:lr,panOnScrollMode:Or,panOnDrag:Fr,autoPanOnSelection:Vr,onPaneClick:ur,onPaneMouseEnter:cr,onPaneMouseMove:Ft,onPaneMouseLeave:dt,onPaneScroll:Bn,onPaneContextMenu:Vn,paneClickDistance:Nn,nodeClickDistance:Wn,onSelectionContextMenu:U,onSelectionStart:M,onSelectionEnd:D,onReconnect:it,onReconnectStart:dr,onReconnectEnd:bn,onEdgeContextMenu:Pt,onEdgeDoubleClick:nn,onEdgeMouseEnter:xo,onEdgeMouseMove:Ze,onEdgeMouseLeave:He,reconnectRadius:En,defaultMarkerColor:kn,noDragClassName:Hr,noWheelClassName:on,noPanClassName:It,rfId:sn,disableKeyboardA11y:fr,nodeExtent:Mt,viewport:hi,onViewportChange:pi,nodesDraggable:Le}),d.jsx(R_,{onSelectionChange:Q}),jn,d.jsx(E_,{proOptions:Rt,position:_o}),d.jsx(b_,{rfId:sn,disableKeyboardA11y:fr})]})})}var dk=Gg(ck);function fk({dimensions:t,lineWidth:r,variant:o,className:s}){return d.jsx("path",{strokeWidth:r,d:`M${t[0]/2} 0 V${t[1]} M0 ${t[1]/2} H${t[0]}`,className:ot(["react-flow__background-pattern",o,s])})}function hk({radius:t,className:r}){return d.jsx("circle",{cx:t,cy:t,r:t,className:ot(["react-flow__background-pattern","dots",r])})}var zr;(function(t){t.Lines="lines",t.Dots="dots",t.Cross="cross"})(zr||(zr={}));const pk={[zr.Dots]:1,[zr.Lines]:1,[zr.Cross]:6},gk=t=>({transform:t.transform,patternId:`pattern-${t.rfId}`});function xm({id:t,variant:r=zr.Dots,gap:o=20,size:s,lineWidth:a=1,offset:u=0,color:c,bgColor:h,style:p,className:y,patternClassName:x}){const v=L.useRef(null),{transform:g,patternId:_}=De(gk,Qe),S=s||pk[r],N=r===zr.Dots,b=r===zr.Cross,E=Array.isArray(o)?o:[o,o],I=[E[0]*g[2]||1,E[1]*g[2]||1],w=S*g[2],j=Array.isArray(u)?u:[u,u],A=b?[w,w]:I,$=[j[0]*g[2]+A[0]/2,j[1]*g[2]+A[1]/2],F=`${_}${t||""}`;return d.jsxs("svg",{className:ot(["react-flow__background",y]),style:{...p,...ul,"--xy-background-color-props":h,"--xy-background-pattern-color-props":c},ref:v,"data-testid":"rf__background",children:[d.jsx("pattern",{id:F,x:g[0]%I[0],y:g[1]%I[1],width:I[0],height:I[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${$[0]},-${$[1]})`,children:N?d.jsx(hk,{radius:w/2,className:x}):d.jsx(fk,{dimensions:A,lineWidth:a,variant:r,className:x})}),d.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${F})`})]})}xm.displayName="Background";const mk=L.memo(xm);function yk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:d.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function vk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:d.jsx("path",{d:"M0 0h32v4.2H0z"})})}function xk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:d.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function wk(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function _k(){return d.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:d.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function Pa({children:t,className:r,...o}){return d.jsx("button",{type:"button",className:ot(["react-flow__controls-button",r]),...o,children:t})}const Sk=t=>({isInteractive:t.nodesDraggable||t.nodesConnectable||t.elementsSelectable,minZoomReached:t.transform[2]<=t.minZoom,maxZoomReached:t.transform[2]>=t.maxZoom,ariaLabelConfig:t.ariaLabelConfig});function wm({style:t,showZoom:r=!0,showFitView:o=!0,showInteractive:s=!0,fitViewOptions:a,onZoomIn:u,onZoomOut:c,onFitView:h,onInteractiveChange:p,className:y,children:x,position:v="bottom-left",orientation:g="vertical","aria-label":_}){const S=Ge(),{isInteractive:N,minZoomReached:b,maxZoomReached:E,ariaLabelConfig:I}=De(Sk,Qe),{zoomIn:w,zoomOut:j,fitView:A}=ll(),$=()=>{w(),u==null||u()},F=()=>{j(),c==null||c()},Y=()=>{A(a),h==null||h()},q=()=>{S.setState({nodesDraggable:!N,nodesConnectable:!N,elementsSelectable:!N}),p==null||p(!N)},re=g==="horizontal"?"horizontal":"vertical";return d.jsxs(al,{className:ot(["react-flow__controls",re,y]),position:v,style:t,"data-testid":"rf__controls","aria-label":_??I["controls.ariaLabel"],children:[r&&d.jsxs(d.Fragment,{children:[d.jsx(Pa,{onClick:$,className:"react-flow__controls-zoomin",title:I["controls.zoomIn.ariaLabel"],"aria-label":I["controls.zoomIn.ariaLabel"],disabled:E,children:d.jsx(yk,{})}),d.jsx(Pa,{onClick:F,className:"react-flow__controls-zoomout",title:I["controls.zoomOut.ariaLabel"],"aria-label":I["controls.zoomOut.ariaLabel"],disabled:b,children:d.jsx(vk,{})})]}),o&&d.jsx(Pa,{className:"react-flow__controls-fitview",onClick:Y,title:I["controls.fitView.ariaLabel"],"aria-label":I["controls.fitView.ariaLabel"],children:d.jsx(xk,{})}),s&&d.jsx(Pa,{className:"react-flow__controls-interactive",onClick:q,title:I["controls.interactive.ariaLabel"],"aria-label":I["controls.interactive.ariaLabel"],children:N?d.jsx(_k,{}):d.jsx(wk,{})}),x]})}wm.displayName="Controls";const kk=L.memo(wm);function Nk({id:t,x:r,y:o,width:s,height:a,style:u,color:c,strokeColor:h,strokeWidth:p,className:y,borderRadius:x,shapeRendering:v,selected:g,onClick:_}){const{background:S,backgroundColor:N}=u||{},b=c||S||N;return d.jsx("rect",{className:ot(["react-flow__minimap-node",{selected:g},y]),x:r,y:o,rx:x,ry:x,width:s,height:a,style:{fill:b,stroke:h,strokeWidth:p},shapeRendering:v,onClick:_?E=>_(E,t):void 0})}const jk=L.memo(Nk),bk=t=>t.nodes.map(r=>r.id),tc=t=>t instanceof Function?t:()=>t;function Ek({nodeStrokeColor:t,nodeColor:r,nodeClassName:o="",nodeBorderRadius:s=5,nodeStrokeWidth:a,nodeComponent:u=jk,onClick:c}){const h=De(bk,Qe),p=tc(r),y=tc(t),x=tc(o),v=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return d.jsx(d.Fragment,{children:h.map(g=>d.jsx(Mk,{id:g,nodeColorFunc:p,nodeStrokeColorFunc:y,nodeClassNameFunc:x,nodeBorderRadius:s,nodeStrokeWidth:a,NodeComponent:u,onClick:c,shapeRendering:v},g))})}function Ck({id:t,nodeColorFunc:r,nodeStrokeColorFunc:o,nodeClassNameFunc:s,nodeBorderRadius:a,nodeStrokeWidth:u,shapeRendering:c,NodeComponent:h,onClick:p}){const{node:y,x,y:v,width:g,height:_}=De(S=>{const N=S.nodeLookup.get(t);if(!N)return{node:void 0,x:0,y:0,width:0,height:0};const b=N.internals.userNode,{x:E,y:I}=N.internals.positionAbsolute,{width:w,height:j}=Sn(b);return{node:b,x:E,y:I,width:w,height:j}},Qe);return!y||y.hidden||!wg(y)?null:d.jsx(h,{x,y:v,width:g,height:_,style:y.style,selected:!!y.selected,className:s(y),color:r(y),borderRadius:a,strokeColor:o(y),strokeWidth:u,shapeRendering:c,onClick:p,id:y.id})}const Mk=L.memo(Ck);var Pk=L.memo(Ek);const Ik=200,Rk=150,Tk=t=>!t.hidden,Lk=t=>{const r={x:-t.transform[0]/t.transform[2],y:-t.transform[1]/t.transform[2],width:t.width/t.transform[2],height:t.height/t.transform[2]};return{viewBB:r,boundingRect:t.nodeLookup.size>0?yg(ys(t.nodeLookup,{filter:Tk}),r):r,rfId:t.rfId,panZoom:t.panZoom,translateExtent:t.translateExtent,flowWidth:t.width,flowHeight:t.height,ariaLabelConfig:t.ariaLabelConfig}},xp=(t,r)=>t.x===r.x&&t.y===r.y&&t.width===r.width&&t.height===r.height,Ak=(t,r)=>xp(t.viewBB,r.viewBB)&&xp(t.boundingRect,r.boundingRect)&&t.rfId===r.rfId&&t.panZoom===r.panZoom&&t.translateExtent===r.translateExtent&&t.flowWidth===r.flowWidth&&t.flowHeight===r.flowHeight&&t.ariaLabelConfig===r.ariaLabelConfig,$k="react-flow__minimap-desc";function _m({style:t,className:r,nodeStrokeColor:o,nodeColor:s,nodeClassName:a="",nodeBorderRadius:u=5,nodeStrokeWidth:c,nodeComponent:h,bgColor:p,maskColor:y,maskStrokeColor:x,maskStrokeWidth:v,position:g="bottom-right",onClick:_,onNodeClick:S,pannable:N=!1,zoomable:b=!1,ariaLabel:E,inversePan:I,zoomStep:w=1,offsetScale:j=5}){const A=Ge(),$=L.useRef(null),{boundingRect:F,viewBB:Y,rfId:q,panZoom:re,translateExtent:J,flowWidth:te,flowHeight:Q,ariaLabelConfig:C}=De(Lk,Ak),V=(t==null?void 0:t.width)??Ik,W=(t==null?void 0:t.height)??Rk,U=F.width/V,M=F.height/W,D=Math.max(U,M),H=D*V,R=D*W,z=j*D,ne=F.x-(H-F.width)/2-z,oe=F.y-(R-F.height)/2-z,fe=H+z*2,he=R+z*2,pe=`${$k}-${q}`,Z=L.useRef(0),se=L.useRef();Z.current=D,L.useEffect(()=>{if($.current&&re)return se.current=X1({domNode:$.current,panZoom:re,getTransform:()=>A.getState().transform,getViewScale:()=>Z.current}),()=>{var ve;(ve=se.current)==null||ve.destroy()}},[re]),L.useEffect(()=>{var ve;(ve=se.current)==null||ve.update({translateExtent:J,width:te,height:Q,inversePan:I,pannable:N,zoomStep:w,zoomable:b})},[N,b,I,w,J,te,Q]);const me=_?ve=>{var je;const[Pe,ue]=((je=se.current)==null?void 0:je.pointer(ve))||[0,0];_(ve,{x:Pe,y:ue})}:void 0,Ne=S?L.useCallback((ve,Pe)=>{const ue=A.getState().nodeLookup.get(Pe).internals.userNode;S(ve,ue)},[]):void 0,we=E??C["minimap.ariaLabel"];return d.jsx(al,{position:g,style:{...t,"--xy-minimap-background-color-props":typeof p=="string"?p:void 0,"--xy-minimap-mask-background-color-props":typeof y=="string"?y:void 0,"--xy-minimap-mask-stroke-color-props":typeof x=="string"?x:void 0,"--xy-minimap-mask-stroke-width-props":typeof v=="number"?v*D:void 0,"--xy-minimap-node-background-color-props":typeof s=="string"?s:void 0,"--xy-minimap-node-stroke-color-props":typeof o=="string"?o:void 0,"--xy-minimap-node-stroke-width-props":typeof c=="number"?c:void 0},className:ot(["react-flow__minimap",r]),"data-testid":"rf__minimap",children:d.jsxs("svg",{width:V,height:W,viewBox:`${ne} ${oe} ${fe} ${he}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":pe,ref:$,onClick:me,children:[we&&d.jsx("title",{id:pe,children:we}),d.jsx(Pk,{onClick:Ne,nodeColor:s,nodeStrokeColor:o,nodeBorderRadius:u,nodeClassName:a,nodeStrokeWidth:c,nodeComponent:h}),d.jsx("path",{className:"react-flow__minimap-mask",d:`M${ne-z},${oe-z}h${fe+z*2}v${he+z*2}h${-fe-z*2}z - M${Y.x},${Y.y}h${Y.width}v${Y.height}h${-Y.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}_m.displayName="MiniMap";const zk=L.memo(_m),Dk=t=>r=>t?`${Math.max(1/r.transform[2],1)}`:void 0,Ok={[oi.Line]:"right",[oi.Handle]:"bottom-right"};function Fk({nodeId:t,position:r,variant:o=oi.Handle,className:s,style:a=void 0,children:u,color:c,minWidth:h=10,minHeight:p=10,maxWidth:y=Number.MAX_VALUE,maxHeight:x=Number.MAX_VALUE,keepAspectRatio:v=!1,resizeDirection:g,autoScale:_=!0,shouldResize:S,onResizeStart:N,onResize:b,onResizeEnd:E}){const I=Qg(),w=typeof t=="string"?t:I,j=Ge(),A=L.useRef(null),$=o===oi.Handle,F=De(L.useCallback(Dk($&&_),[$,_]),Qe),Y=L.useRef(null),q=r??Ok[o];L.useEffect(()=>{if(!(!A.current||!w))return Y.current||(Y.current=a_({domNode:A.current,nodeId:w,getStoreItems:()=>{const{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,domNode:W}=j.getState();return{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,paneDomNode:W}},onChange:(J,te)=>{const{triggerNodeChanges:Q,nodeLookup:C,parentLookup:V,nodeOrigin:W}=j.getState(),U=[],M={x:J.x,y:J.y},D=C.get(w);if(D&&D.expandParent&&D.parentId){const H=D.origin??W,R=J.width??D.measured.width??0,z=J.height??D.measured.height??0,ne={id:D.id,parentId:D.parentId,rect:{width:R,height:z,..._g({x:J.x??D.position.x,y:J.y??D.position.y},{width:R,height:z},D.parentId,C,H)}},oe=$c([ne],C,V,W);U.push(...oe),M.x=J.x?Math.max(H[0]*R,J.x):void 0,M.y=J.y?Math.max(H[1]*z,J.y):void 0}if(M.x!==void 0&&M.y!==void 0){const H={id:w,type:"position",position:{...M}};U.push(H)}if(J.width!==void 0&&J.height!==void 0){const R={id:w,type:"dimensions",resizing:!0,setAttributes:g?g==="horizontal"?"width":"height":!0,dimensions:{width:J.width,height:J.height}};U.push(R)}for(const H of te){const R={...H,type:"position"};U.push(R)}Q(U)},onEnd:({width:J,height:te})=>{const Q={id:w,type:"dimensions",resizing:!1,dimensions:{width:J,height:te}};j.getState().triggerNodeChanges([Q])}})),Y.current.update({controlPosition:q,boundaries:{minWidth:h,minHeight:p,maxWidth:y,maxHeight:x},keepAspectRatio:v,resizeDirection:g,onResizeStart:N,onResize:b,onResizeEnd:E,shouldResize:S}),()=>{var J;(J=Y.current)==null||J.destroy()}},[q,h,p,y,x,v,N,b,E,S]);const re=q.split("-");return d.jsx("div",{className:ot(["react-flow__resize-control","nodrag",...re,o,s]),ref:A,style:{...a,scale:F,...c&&{[$?"backgroundColor":"borderColor"]:c}},children:u})}L.memo(Fk);const Hk={"arch.context":0,"django.app":0,"django.route":1,"django.websocket_route":1,"fastapi.route":1,"django.url_name":2,"django.view":3,"django.viewset_action":3,"django.permission":3,"django.throttle":3,"django.serializer":4,"django.form":4,"graphql.type":4,"fastapi.model":4,"django.serializer_field":5,"django.service":5,"graphql.field":5,"django.model":6,"django.field":7,"django.relation":7,"django.task":8,"django.receiver":8,"django.signal":8,"django.test":8,"django.migration_op":8,"django.admin":8,"django.management_command":8,"django.consumer":8,"django.cache_key":8,"django.feature_flag":8,"django.side_effect":8,"openapi.path":9,"graphql.operation":9,"react.api_client":10,"django.htmx":10,"react.query_key":11,"react.hook":11,"react.feature":11,"react.route":12,"react.page":12,"react.server_action":12,"django.template":12,"react.component":13,"react.context":13,"react.form_schema":14,"react.test":14};function si(t){return Hk[t]??8}const zn=208,Dr=64,ai=88,Dc=28,Bk=8;function Vk(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function Sm(t,r=[]){const o=new Map;if(!t.length)return o;const s=new Map;for(const w of t){const j=si(w.type),A=s.get(j)??[];A.push(w),s.set(j,A)}const u=[...s.keys()].sort((w,j)=>w-j).map(w=>[...s.get(w)??[]].sort((j,A)=>j.name.localeCompare(A.name)||j.id.localeCompare(A.id))),c=new Set(t.map(w=>w.id)),h=new Map,p=new Map;for(const w of t)h.set(w.id,[]),p.set(w.id,[]);for(const w of r)!c.has(w.src)||!c.has(w.dst)||w.src===w.dst||(p.get(w.src).push(w.dst),h.get(w.dst).push(w.src));const y=new Map;u.forEach((w,j)=>{for(const A of w)y.set(A.id,j)});const x=new Map,v=()=>{for(const w of u)w.forEach((j,A)=>x.set(j.id,A))};v();const g=(w,j)=>{const A=w.map(($,F)=>{const Y=j($.id).map(re=>x.get(re)).filter(re=>re!==void 0),q=Vk(Y);return{n:$,bary:Number.isNaN(q)?F:q,name:$.name,id:$.id}});return A.sort(($,F)=>$.bary-F.bary||$.name.localeCompare(F.name)||$.id.localeCompare(F.id)),A.map($=>$.n)},_=w=>j=>y.get(j)===w;for(let w=0;w(h.get(A)??[]).filter(_(j-1))),v();for(let j=u.length-2;j>=0;j--)u[j]=g(u[j],A=>(p.get(A)??[]).filter(_(j+1))),v()}const S=zn+ai,N=Dr+Dc,b=Math.max(...u.map(w=>w.length),1),E=[];let I=0;for(let w=0;wY.id)),A=new Set((u[w+1]??[]).map(Y=>Y.id));let $=0;if(A.size)for(const Y of r)j.has(Y.src)&&A.has(Y.dst)&&($+=1);const F=Math.min(120,Math.max(0,($-2)*12));I+=S+F}return u.forEach((w,j)=>{const A=(b-w.length)*N/2;w.forEach(($,F)=>{o.set($.id,{x:E[j]??0,y:A+F*N})})}),o}const xc=[{id:"layers",label:"Architecture layers"},{id:"flow",label:"Edge flow"},{id:"radial",label:"Radial"},{id:"grid",label:"Compact grid"}],Wk=new Set(xc.map(t=>t.id)),km="loadpath.graphLayout",Uk=8,Gk=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","openapi.path","django.consumer","django.websocket_route","django.template","graphql.operation","fastapi.route"]),Nm=90,Yk=new Set(["django.field","django.serializer_field","django.relation","django.test","react.test","graphql.field","django.url_name","django.throttle"]),wp={"arch.context":"#edf2f4","django.app":"#8d99ae","django.route":"#4cc9f0","django.url_name":"#4cc9f0","django.view":"#4895ef","django.viewset_action":"#4361ee","django.permission":"#7b8cde","django.serializer":"#f4a261","django.form":"#e9c46a","django.serializer_field":"#e9c46a","django.service":"#90be6d","django.model":"#2a9d8f","django.field":"#8ac926","django.task":"#e76f51","django.receiver":"#e85d04","django.signal":"#f4a261","django.test":"#6c757d","django.admin":"#adb5bd","django.migration_op":"#9d4edd","django.consumer":"#e76f51","django.websocket_route":"#4cc9f0","django.template":"#c77dff","django.htmx":"#ff6b6b","django.cache_key":"#6c757d","django.feature_flag":"#f4a261","django.side_effect":"#e85d04","graphql.type":"#00bbf9","graphql.operation":"#00bbf9","fastapi.route":"#4cc9f0","fastapi.model":"#f4a261","openapi.path":"#00bbf9","react.api_client":"#ff6b6b","react.query_key":"#adb5bd","react.hook":"#7b2cbf","react.feature":"#9d4edd","react.route":"#c77dff","react.page":"#c77dff","react.server_action":"#e76f51","react.component":"#9d4edd","react.form_schema":"#ffd166","react.test":"#6c757d"},Xk=Math.PI*(3-Math.sqrt(5)),jm=220,qk=26,Kk={0:"context",1:"routes",2:"url names",3:"views",4:"serializers",5:"services",6:"models",7:"fields",8:"jobs / signals",9:"openapi",10:"api client",11:"hooks",12:"pages",13:"components",14:"forms / tests"};function bm(t){return t.startsWith("react.")?"react":t.startsWith("openapi.")||t.startsWith("graphql.")||t.startsWith("fastapi.")?"stitch":t.startsWith("arch.")?"arch":"django"}function aj(t){return wp[t]?wp[t]:t.startsWith("react.")?"#9d4edd":t.startsWith("openapi.")?"#00bbf9":"#4a5568"}function Qk(t){return t>=Nm?"3d":"2d"}function Zk(t){return t>=Nm?"overview":"full"}function Jk(t,r,o=1){const s=new Set([t]);let a=new Set([t]);for(let u=0;uo.families.has(bm(h.type)));o.detail==="overview"&&(s=s.filter(h=>!Yk.has(h.type)));const a=new Set(s.map(h=>h.id)),u=r.filter(h=>a.has(h.src)&&a.has(h.dst)),c=o.focusId?Jk(o.focusId,u,1):new Set;if(o.neighborhoodOnly&&o.focusId&&c.size){s=s.filter(p=>c.has(p.id));const h=new Set(s.map(p=>p.id));return{nodes:s,edges:u.filter(p=>h.has(p.src)&&h.has(p.dst)),neighborIds:c}}return{nodes:s,edges:u,neighborIds:c}}function tN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>`${s.name} ${s.qualified_name} ${s.type} ${s.file_path||""} ${s.context||""}`.toLowerCase().includes(o)).slice(0,24):[]}function nN(t,r,o,s){const a=new Set(t.map(N=>N.id));if(!a.has(o))return{nodeIds:new Set,edgeIds:new Set};const u=new Map,c=new Map;for(const N of r){if(!a.has(N.src)||!a.has(N.dst))continue;const b=u.get(N.src)??[];b.push({dst:N.dst,id:N.id}),u.set(N.src,b);const E=c.get(N.dst)??[];E.push({src:N.src,id:N.id}),c.set(N.dst,E)}const h=new Set(t.filter(N=>Gk.has(N.type)).map(N=>N.id)),p=h.size?h:a,y=new Set,x=[o];for(;x.length;){const N=x.pop();if(!y.has(N)){y.add(N);for(const b of u.get(N)??[])y.has(b.dst)||x.push(b.dst)}}const v=new Set([o]),g=[...p].filter(N=>y.has(N)),_=new Set(g);for(;g.length;){const N=g.pop();v.add(N);for(const b of c.get(N)??[])y.has(b.src)&&!_.has(b.src)&&(_.add(b.src),g.push(b.src))}const S=new Set;for(const N of r)v.has(N.src)&&v.has(N.dst)&&S.add(N.id);return{nodeIds:v,edgeIds:S}}function lj(t){const r=new Map;for(const s of t){const a=si(s.type),u=r.get(a)??[];u.push(s),r.set(a,u)}const o=new Map;for(const[s,a]of r){a.sort((c,h)=>c.name.localeCompare(h.name));const u=s*jm;a.forEach((c,h)=>{if(a.length===1){o.set(c.id,{x:u,y:0,z:0});return}const p=qk*Math.sqrt(h+1),y=h*Xk;o.set(c.id,{x:u,y:p*Math.cos(y),z:p*Math.sin(y)})})}return o}function uj(t){const r=new Map;for(const o of t){const s=si(o.type);r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>o[0]-s[0]).map(([o,s])=>({layer:o,x:o*jm,count:s}))}function rN(){try{if(typeof localStorage>"u")return"layers";const t=localStorage.getItem(km);return t&&Wk.has(t)?t:"layers"}catch{return"layers"}}function oN(t){try{if(typeof localStorage>"u")return;localStorage.setItem(km,t)}catch{}}function iN(t){return t==="layers"||t==="flow"}function sN(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function ts(t,r){return t.name.localeCompare(r.name)||t.id.localeCompare(r.id)}function aN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.flat().map(S=>S.id)),a=new Map,u=new Map;for(const S of t.flat())a.set(S.id,[]),u.set(S.id,[]);for(const S of r)!s.has(S.src)||!s.has(S.dst)||S.src===S.dst||(u.get(S.src).push(S.dst),a.get(S.dst).push(S.src));const c=new Map;t.forEach((S,N)=>{for(const b of S)c.set(b.id,N)});const h=new Map,p=()=>{for(const S of t)S.forEach((N,b)=>h.set(N.id,b))};p();const y=(S,N)=>{const b=S.map((E,I)=>{const w=N(E.id).map(A=>h.get(A)).filter(A=>A!==void 0),j=sN(w);return{n:E,bary:Number.isNaN(j)?I:j,name:E.name,id:E.id}});return b.sort((E,I)=>E.bary-I.bary||E.name.localeCompare(I.name)||E.id.localeCompare(I.id)),b.map(E=>E.n)},x=S=>N=>c.get(N)===S;for(let S=0;S(a.get(b)??[]).filter(x(N-1))),p();for(let N=t.length-2;N>=0;N--)t[N]=y(t[N],b=>(u.get(b)??[]).filter(x(N+1))),p()}const v=zn+ai,g=Dr+Dc,_=Math.max(...t.map(S=>S.length),1);return t.forEach((S,N)=>{const b=(_-S.length)*g/2;S.forEach((E,I)=>{o.set(E.id,{x:N*v,y:b+I*g})})}),o}function lN(t,r){const o=new Set(t.map(h=>h.id)),s=Math.max(t.length-1,0),a=new Map;for(const h of t)a.set(h.id,0);for(let h=0;h(a.get(y.dst)||0)&&(a.set(y.dst,x),p=!0)}if(!p)break}const u=new Map;for(const h of t){const p=a.get(h.id)||0,y=u.get(p)??[];y.push(h),u.set(p,y)}const c=[...u.keys()].sort((h,p)=>h-p).map(h=>(u.get(h)??[]).sort(ts));return aN(c,r)}function uN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.map(g=>g.id)),a=new Map,u=new Map;for(const g of t)a.set(g.id,[]),u.set(g.id,0);for(const g of r)!s.has(g.src)||!s.has(g.dst)||g.src===g.dst||(a.get(g.src).push(g.dst),a.get(g.dst).push(g.src),u.set(g.src,(u.get(g.src)||0)+1),u.set(g.dst,(u.get(g.dst)||0)+1));const c=[...t].sort((g,_)=>(u.get(_.id)||0)-(u.get(g.id)||0)||ts(g,_))[0]??t[0],h=new Map,p=[[c]];h.set(c.id,0);const y=[c];for(;y.length;){const g=y.shift(),_=h.get(g.id)||0,S=(a.get(g.id)??[]).map(N=>t.find(b=>b.id===N)).filter(N=>!!N).sort(ts);for(const N of S){if(h.has(N.id))continue;h.set(N.id,_+1);const b=p[_+1]??[];b.push(N),p[_+1]=b,y.push(N)}}const x=t.filter(g=>!h.has(g.id)).sort(ts);x.length&&p.push(x);const v=zn+32;return p.forEach((g,_)=>{if(_===0&&g.length===1){o.set(g[0].id,{x:0,y:0});return}const S=Math.max(_*(zn+ai),g.length<=1?zn:g.length*v/(2*Math.PI));g.forEach((N,b)=>{const E=-Math.PI/2+2*Math.PI*b/g.length;o.set(N.id,{x:Math.cos(E)*S,y:Math.sin(E)*S})})}),o}function cN(t){const r=new Map,o=[...t].sort((c,h)=>si(c.type)-si(h.type)||ts(c,h)),s=Math.max(1,Math.ceil(Math.sqrt(o.length))),a=zn+ai,u=Dr+Dc;return o.forEach((c,h)=>{r.set(c.id,{x:h%s*a,y:Math.floor(h/s)*u})}),r}function dN(t,r=[],o="layers"){return o==="flow"?lN(t,r):o==="radial"?uN(t,r):o==="grid"?cN(t):Sm(t,r)}const Ia=16,fN=12,hN=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","django.throttle","django.admin","django.management_command","openapi.path","django.consumer","django.websocket_route","django.template","django.cache_key","django.feature_flag","django.side_effect","graphql.operation","fastapi.route"]),pN=new Set(["django.serializer","django.serializer_field","django.form","openapi.path","react.form_schema","django.route","graphql.type","graphql.field","graphql.operation","fastapi.model","fastapi.route"]),_p={"arch.context":"Ownership boundary from loadpath.yml — the context this code belongs to.","django.app":"Django app package that owns models, views, and jobs.","django.route":"HTTP URL that publishes a view. A sink: this is where a change becomes a public request.","django.url_name":"Named URL used by reverse() / {% url %} lookups.","django.view":"Request handler (class-based view, function view, or ViewSet).","django.viewset_action":"One ViewSet action (list, create, retrieve, update, destroy).","django.permission":"Auth gate on a view — who is allowed to hit this path.","django.throttle":"Rate-limit class attached to a view.","django.serializer":"Request/response contract: which fields go in and come out.","django.form":"Django form or django-filter FilterSet — the typed input contract.","django.serializer_field":"One field on a serializer or form — the typed slot on the contract.","django.service":"Internal service or use-case. Work that is not itself an HTTP sink.","django.model":"ORM model. Schema and relations live here.","django.field":"Model column. Type, indexes, and relations are the contract of the table.","django.relation":"Model-to-model relation (FK / M2M / O2O).","django.task":"Celery or Dramatiq job. Once enqueued, this is a sink.","django.receiver":"Signal handler that runs after a model event.","django.signal":"Django signal that receivers subscribe to.","django.test":"Backend test that mentions symbols on this path.","django.admin":"Django admin class for a model.","django.migration_op":"Schema migration operation (CreateModel, AlterField, …).","django.management_command":"manage.py command — an operational sink.","django.consumer":"Django Channels WebSocket/HTTP consumer. A sink once a client connects.","django.websocket_route":"ASGI WebSocket URL. A sink: this is where a change becomes a live connection.","django.template":"Django template. HTML (and HTMX) the server renders.","django.htmx":"HTMX call from a template to a URL — another published seam.","django.cache_key":"Cache get/set key. Invalidation is part of the load path.","django.feature_flag":"Feature flag checked on this path. The change may be dark-launched.","django.side_effect":"transaction.on_commit (or similar) side effect that runs after the request commits.","graphql.type":"GraphQL object/input type — a published contract.","graphql.field":"One field on a GraphQL type.","graphql.operation":"GraphQL query, mutation, or subscription. A published contract and a sink.","fastapi.route":"FastAPI path operation sitting next to Django in this repo.","fastapi.model":"Pydantic response/request model — the FastAPI contract.","openapi.path":"Generated OpenAPI operation. The typed HTTP contract between stacks.","react.api_client":"Frontend fetch or generated client call to an API path.","react.query_key":"React Query cache key. Invalidation and reads share this name.","react.hook":"Data hook wrapping query or mutation calls.","react.feature":"Frontend feature module (folder).","react.route":"Client-side route. A sink: this is a URL the user can open.","react.page":"Page or screen component rendered by a route.","react.server_action":"Next.js Server Action. A sink: the mutation runs on the server.","react.component":"UI component.","react.form_schema":"Zod (or similar) schema — typed form inputs on the client.","react.test":"Frontend test covering a page, hook, or component.","react.context":"React context provider."},gN={field_type:"Type",fields:"Fields",form_fields:"Form fields",permissions:"Permissions",throttles:"Throttles",authentication:"Authentication",pagination:"Pagination",filterset:"Filterset",bases:"Extends",on_delete:"on_delete",related_name:"related_name",unique:"Unique",db_index:"Indexed",relation:"Relation field",looks_idempotent_on_pk:"Idempotent on pk",broker:"Broker",route:"Route",url_name:"URL name",view:"View",include:"Includes",mounted_at:"Mounted at",full_path:"Full path",method:"Method",path:"Path",operation_id:"Operation",raw:"URL",kind:"Schema",exclude:"Excludes",queryset_in_serializer:"Queryset in serializer",get_queryset:"Custom get_queryset",get_serializer_class:"Dynamic serializer",dynamic:"Dynamic",fbv:"Function view",next_app:"Next.js App Router",next_pages:"Next.js Pages Router",next_kind:"Next file",next_layout:"Layout",server_action:"Server Action",typed_client:"Typed client",endpoint:"Endpoint",procedure:"Procedure",e2e:"E2E",visits:"Visits",nested_serializer:"Nested serializer",nested_serializers:"Nested serializers",method_field:"SerializerMethodField",method_fields:"Method fields",from_to_representation:"to_representation",to_representation_fields:"to_representation fields",to_representation:"Custom to_representation",serializer_classes:"get_serializer_class returns",get_serializer_class_resolved:"Serializer resolved",ninja_schema:"Ninja Schema",pydantic:"Pydantic",django_form:"Django form",mutation:"Mutation",has_error_boundary:"Error boundary",invalidation:"Cache invalidation",inferred:"Inferred stitch",generated:"Generated",shared:"Shared module",element:"Renders",model_name:"Model",field_name:"Field",op:"Operation",app:"App",feature:"Feature",from_view:"From view",mentions:"Mentions",nodeid:"Test id",task:"Task",to:"Related to",doc:"Summary",template:"Template",signal:"Signal",sender:"Sender",decorators:"Decorators",nplusone:"N+1 risk",lookups:"Lookups",null:"NULL",blank:"Blank",default:"Default",max_length:"max_length",max_digits:"max_digits",decimal_places:"decimal_places",primary_key:"Primary key",help_text:"Help text",choices:"Choices",auto_now:"auto_now",auto_now_add:"auto_now_add",basename:"Router basename",args:"Args",beat:"Beat",schedule_name:"Schedule",websocket:"WebSocket",htmx:"HTMX",blocks:"Blocks",db_table:"db_table"},Sp=["doc","field_type","method","path","operation_id","raw","route","mounted_at","full_path","url_name","view","element","fields","form_fields","exclude","nested_serializer","nested_serializers","method_fields","to_representation_fields","serializer_classes","typed_client","endpoint","procedure","visits","kind","bases","permissions","authentication","throttles","pagination","filterset","on_delete","related_name","to","unique","db_index","null","blank","default","max_length","max_digits","decimal_places","primary_key","auto_now","auto_now_add","help_text","choices","relation","nplusone","lookups","template","signal","sender","decorators","basename","args","beat","schedule_name","websocket","htmx","blocks","db_table","looks_idempotent_on_pk","broker","task","model_name","field_name","op","app","feature","from_view","include","fbv","ninja","django_form","mutation","has_error_boundary","invalidation","inferred","generated","shared","queryset_in_serializer","get_queryset","get_serializer_class","dynamic","mentions","nodeid"],kp=new Set(["referenced","placeholder","booted","line","call","from","import","local","source","file","plain_handler","string_ref","pagination_sink","match","via","generated_client","django","react","superseded_by_generated","foreign_app","imported"]),mN=new Set(["looks_idempotent_on_pk","null","blank"]),yN=new Set(["inferred","generated","mutation","fbv","ninja","filterset","next_app","next_pages","server_action","e2e","ninja_schema","pydantic","method_field","trpc"]);function vN(t){return _p[t]?_p[t]:t.startsWith("react.")?"A React node on the load path.":t.startsWith("django.")?"A Django node on the load path.":t.startsWith("openapi.")?"A stitch node between Django and React.":"A node on the architecture graph."}function xN(t,r,o){const s=new Map(r.map(g=>[g.id,g])),a=[];hN.has(t.type)&&a.push("sink"),pN.has(t.type)&&a.push("contract");const u=t.extra??{};u.inferred&&a.push("inferred"),u.generated&&a.push("generated"),u.mutation&&a.push("mutation"),u.fbv&&a.push("function view"),u.ninja&&a.push("ninja"),u.ninja_schema&&a.push("ninja schema"),u.next_app&&a.push("app router"),u.typed_client&&a.push(String(u.typed_client)),u.e2e&&a.push("e2e"),u.filterset===!0&&a.push("filterset");const c=o.filter(g=>g.dst===t.id),h=o.filter(g=>g.src===t.id),p=c.slice(0,Ia).map(g=>Ra(g,s,g.src)),y=h.slice(0,Ia).map(g=>Ra(g,s,g.dst)),x=t.file_path?`${t.file_path}${t.start_line?`:${t.start_line}`:""}`:void 0,v={type:t.type,typeLabel:ns(li(t.type)),layer:Kk[si(t.type)]??"other",purpose:vN(t.type),name:t.name,qualifiedName:t.qualified_name,file:x,context:t.context,roles:a,facts:_N(u).filter(g=>!(g.key==="app"&&g.value===t.context)),inputs:p,outputs:y,extraInputs:Math.max(0,c.length-Ia),extraOutputs:Math.max(0,h.length-Ia),degreeIn:c.length,degreeOut:h.length,inputKinds:Np(c.map(g=>Ra(g,s,g.src))),outputKinds:Np(h.map(g=>Ra(g,s,g.dst))),pathSummary:""};return v.pathSummary=wN(v),v}function Np(t){const r=new Map;for(const o of t){const s=o.edgeLabel||o.edgeType.replaceAll("_"," ");r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>s[1]-o[1]||o[0].localeCompare(s[0])).map(([o,s])=>({label:o,count:s}))}function wN(t){const r=t.inputKinds.map(s=>`${s.label} ×${s.count}`).join(", "),o=t.outputKinds.map(s=>`${s.label} ×${s.count}`).join(", ");return r&&o?`${r} → this → ${o}`:o?`this → ${o}`:r?`${r} → this`:""}function Ra(t,r,o){const s=r.get(o),a=o.includes(":")?o.slice(o.indexOf(":")+1):o;return{id:o,name:(s==null?void 0:s.name)||a,type:(s==null?void 0:s.type)||"",typeLabel:s?ns(li(s.type)):"",edgeType:t.type,edgeLabel:ns(t.type),inferred:t.confidence<.8}}function _N(t){const r=[...Sp.filter(a=>a in t),...Object.keys(t).filter(a=>!Sp.includes(a)&&!kp.has(a))],o=[],s=new Set;for(const a of r){if(s.has(a)||kp.has(a)||yN.has(a))continue;s.add(a);const u=SN(a,t[a]);u!=null&&o.push({key:a,label:gN[a]??ns(a),value:u})}return o}function SN(t,r){if(r==null)return null;if(typeof r=="boolean")return!r&&!mN.has(t)?null:r?"yes":"no";if(typeof r=="number")return String(r);if(typeof r=="string")return r.trim()||null;if(Array.isArray(r)){if(r.some(u=>u&&typeof u=="object"))return kN(t,r);const o=r.map(u=>typeof u=="string"||typeof u=="number"?String(u):"").filter(Boolean);if(!o.length)return null;const s=o.slice(0,fN),a=o.length-s.length;return a>0?`${s.join(", ")} +${a} more`:s.join(", ")}return null}function kN(t,r){const o=r.slice(0,4).map(a=>{if(t==="nplusone"){const c=String(a.queryset||"queryset"),h=Array.isArray(a.accessed)?a.accessed.join("."):"",p=a.line?` L${a.line}`:"";return h?`${c} → ${h}${p}`:`${c}${p}`}if(t==="lookups"){const c=Array.isArray(a.fields)?a.fields.join(", "):"",h=String(a.kind||"filter");return c?`${h} ${c}`:h}return Object.entries(a).filter(([,c])=>c!=null&&(typeof c=="string"||typeof c=="number")).slice(0,3).map(([c,h])=>`${c}=${h}`).join(" ")});if(!o.some(Boolean))return null;const s=r.length-o.length;return s>0?`${o.join("; ")} +${s} more`:o.join("; ")}const jp=12,bp=.2,NN=.8,qa=20,jN=Dr;function bN(t,r,o){const s=o??Sm(t,r),a=[...new Set([...s.values()].map(p=>p.x))].sort((p,y)=>p-y),u=[];for(const p of r){const y=s.get(p.src),x=s.get(p.dst);if(!y||!x)continue;const v=y.y+Dr/2,g=x.y+Dr/2;if(Math.abs(v-g)S.y0-N.y0||S.y1-N.y1||S.id.localeCompare(N.id)),x=MN(y),v=Math.max(0,...x.values())+1,g=y[0].sourceX,_=EN(a,g);for(const S of y){const N=PN(x.get(S.id)??0,v),b=g+qa+Math.max(1,_-2*qa)*N;h.set(S.id,CN(S.sourceX,S.targetX,b))}}return h}function EN(t,r){const o=r-zn,s=t.find(a=>a>o+1);return s===void 0?ai:Math.max(ai,s-r)}function CN(t,r,o){const s=r-t-2*qa;return s<1?.5:Math.min(1,Math.max(0,(o-t-qa)/s))}function MN(t){const r=[],o=new Map;for(const s of t){let a=-1;for(let u=0;ur[u]+jN){a=u;break}a<0?(a=r.length,r.push(s.y1)):r[a]=Math.max(r[a],s.y1),o.set(s.id,a)}return o}function PN(t,r){return r<=1?.5:bp+(NN-bp)*t/(r-1)}const IN=new Set,RN=L.lazy(()=>I0(()=>import("./LayeredGraph3D-Vlmu5bb6.js"),[],import.meta.url).then(t=>({default:t.LayeredGraph3D}))),TN={cheap:"var(--edge-cheap)",expensive:"var(--edge-expensive)",critical:"var(--edge-critical)"},Ka={n:ke.Top,e:ke.Right,s:ke.Bottom,w:ke.Left};function LN(t,r){const o=r.x-t.x,s=r.y-t.y;return Math.abs(o)>=Math.abs(s)?o>=0?{source:"e",target:"w"}:{source:"w",target:"e"}:s>=0?{source:"s",target:"n"}:{source:"n",target:"s"}}function AN({data:t,selected:r}){const o=(t.roles||[]).map(s=>`role-${s}`).join(" ");return d.jsxs("div",{className:["lp-node",r?"selected":"",t.dim?"dim":"",o].filter(Boolean).join(" "),children:[["n","e","s","w"].map(s=>d.jsx(ii,{id:`tgt-${s}`,type:"target",position:Ka[s],isConnectable:!1},`tgt-${s}`)),d.jsx("div",{className:"t",children:li(t.type)}),d.jsx("div",{className:"n",title:t.name,children:Ar(t.name)}),["n","e","s","w"].map(s=>d.jsx(ii,{id:`src-${s}`,type:"source",position:Ka[s],isConnectable:!1},`src-${s}`))]})}const $N={load:AN},zN=new Set(["django","react","stitch","arch"]);function DN({id:t,sourceX:r,sourceY:o,targetX:s,targetY:a,sourcePosition:u,targetPosition:c,style:h,markerEnd:p,markerStart:y,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,data:b,interactionWidth:E}){const[I,w,j]=Ya({sourceX:r,sourceY:o,sourcePosition:u,targetX:s,targetY:a,targetPosition:c,borderRadius:8,stepPosition:(b==null?void 0:b.stepPosition)??.5});return d.jsx(ws,{id:t,path:I,labelX:w,labelY:j,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,style:h,markerEnd:p,markerStart:y,interactionWidth:E})}const ON={loadstep:DN};function FN({topologyKey:t}){const{fitView:r}=ll();return L.useEffect(()=>{let o=0;const s=requestAnimationFrame(()=>{o=requestAnimationFrame(()=>{r({padding:.2,maxZoom:1.15})})});return()=>{cancelAnimationFrame(s),cancelAnimationFrame(o)}},[r,t]),null}function HN(t,r,o=null,s={}){const a=new Map(t.map(v=>[v.id,v])),u=s.layout??"layers",c=iN(u),h=dN(t,r,u),p=bN(t,r,h),y=t.map(v=>{var S;const g=((S=s.roles)==null?void 0:S[v.id])||[],_=!!s.testOverlay&&!g.includes("tested")&&!g.includes("untested")&&!g.includes("test")&&!g.includes("seed");return{id:v.id,type:"load",position:h.get(v.id)??{x:0,y:0},data:{name:v.name,type:v.type,file:v.file_path,roles:g,dim:_},selected:o===v.id,sourcePosition:ke.Right,targetPosition:ke.Left,width:zn,height:Dr,style:{width:zn,height:Dr}}}),x=r.filter(v=>a.has(v.src)&&a.has(v.dst)).map(v=>{const g=TN[v.weight]||"var(--edge-cheap)",_=!!(o&&(v.src===o||v.dst===o)),S=h.get(v.src)??{x:0,y:0},N=h.get(v.dst)??{x:0,y:0},b=c?{source:"e",target:"w"}:LN(S,N);return{id:v.id,source:v.src,target:v.dst,sourceHandle:`src-${b.source}`,targetHandle:`tgt-${b.target}`,sourcePosition:Ka[b.source],targetPosition:Ka[b.target],type:c?"loadstep":"default",animated:v.weight==="critical",data:{stepPosition:p.get(v.id)??.5},style:{stroke:g,strokeWidth:v.weight==="critical"?2.4:1.2,strokeDasharray:v.confidence<.8?"6 4":void 0},markerEnd:{type:us.ArrowClosed,width:14,height:14,color:g},label:_?v.type.replaceAll("_"," "):void 0,labelStyle:_?{fill:"var(--ink)",fontSize:10,fontWeight:600}:void 0,labelBgStyle:_?{fill:"var(--graph-bg)",fillOpacity:.92}:void 0,labelBgPadding:_?[3,5]:void 0,labelBgBorderRadius:_?4:void 0}});return{rfNodes:y,rfEdges:x}}function BN({node:t,nodes:r,edges:o,onClose:s,onWhatIf:a,onSelect:u,onOpenFile:c,pinned:h,onPin:p,onIsolate:y}){const x=xN(t,r,o);return L.useEffect(()=>{const v=g=>{g.key==="Escape"&&s()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[s]),d.jsxs("aside",{className:"inspector","data-testid":"graph-inspector",children:[d.jsxs("div",{className:"inspector-head",children:[d.jsx("div",{className:"t",children:x.typeLabel}),d.jsx("div",{className:"inspector-roles",children:x.roles.map(v=>d.jsx("span",{className:"inspector-chip",children:v},v))}),d.jsx("button",{type:"button",className:"inspector-close","data-testid":"graph-inspector-close","aria-label":"Close inspector",onClick:s,children:"×"})]}),d.jsx("div",{className:"n",children:Ar(x.name)}),d.jsx("p",{className:"inspector-purpose","data-testid":"graph-inspector-purpose",children:x.purpose}),x.context?d.jsx("div",{className:"muted",children:Ar(x.context)}):null,x.file?d.jsxs("div",{className:"file-row",children:[d.jsx("div",{className:"file",children:Ar(x.file)}),c&&t.file_path?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-open-editor",onClick:()=>c(t.file_path,t.start_line),children:"Open in editor"}):null]}):null,d.jsx("div",{className:"muted",children:Ar(x.qualifiedName)}),d.jsxs("div",{className:"muted inspector-layer",children:["layer · ",x.layer]}),d.jsxs("div",{className:"muted inspector-degree","data-testid":"graph-inspector-degree",children:[x.degreeIn," in · ",x.degreeOut," out"]}),x.pathSummary?d.jsx("p",{className:"inspector-path","data-testid":"graph-inspector-path",children:x.pathSummary}):null,x.facts.length?d.jsx("dl",{className:"inspector-facts","data-testid":"graph-inspector-facts",children:x.facts.map(v=>d.jsxs("div",{className:"inspector-fact",children:[d.jsx("dt",{children:v.label}),d.jsx("dd",{children:Ar(v.value)})]},v.key))}):null,d.jsx(Ep,{title:"Inputs",testId:"graph-inspector-inputs",links:x.inputs,extra:x.extraInputs,empty:"Nothing in this graph points here.",onSelect:u}),d.jsx(Ep,{title:"Outputs",testId:"graph-inspector-outputs",links:x.outputs,extra:x.extraOutputs,empty:"This node does not point at anything in this graph.",onSelect:u}),a?d.jsx("p",{className:"whatif-hint","data-testid":"whatif-hint",children:y?"Walks a new path from this node with no git range. Isolate (next) only hides the rest of this map.":"Walks a new path from this node with no git range — as if this changed, regardless of Base/Head."}):null,d.jsxs("div",{className:"btn-row",children:[a?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-whatif",title:"Start a hypothetical walk from this node. Does not use Base/Head.",onClick:()=>a(t.id),children:"What if this changes"}):null,y?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-isolate",title:"Hide nodes that are not on a path from here to a sink. Does not start a new walk.",onClick:()=>y(t.id),children:"Isolate path to sinks"}):null,p?d.jsx("button",{type:"button",className:h?"btn primary":"btn","data-testid":"btn-pin-node",onClick:()=>p(h?null:t.id),children:h?"Unpin":"Pin"}):null]})]})}function Ep({title:t,testId:r,links:o,extra:s,empty:a,onSelect:u}){return d.jsxs("section",{className:"inspector-section","data-testid":r,children:[d.jsxs("h3",{children:[t,d.jsx("span",{className:"count",children:o.length+s})]}),o.length?d.jsx("ul",{children:o.map((c,h)=>d.jsx("li",{children:u?d.jsxs("button",{type:"button",className:"inspector-link",onClick:()=>u(c.id),children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]}):d.jsxs(d.Fragment,{children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]})},`${c.edgeType}:${c.id}:${h}`))}):d.jsx("p",{className:"muted",children:a}),s?d.jsxs("p",{className:"muted",children:["+",s," more"]}):null]})}function nc({nodes:t,edges:r,onWhatIf:o,focusPath:s,selectedId:a,onSelect:u,nodeRoles:c,testOverlay:h=!1,isolateSource:p,onIsolate:y,repoPath:x,onOpenFile:v,pinnedId:g,onPin:_}){const[S,N]=L.useState(null),b=a!==void 0?a:S,E=ue=>{a===void 0&&N(ue),u==null||u(ue)},[I,w]=L.useState(null),[j,A]=L.useState(null),[$,F]=L.useState(()=>rN()),[Y,q]=L.useState(new Set(zN)),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState(!1),W=typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,U=I??Qk(t.length),M=j??Zk(t.length),D=re?b:null,H=L.useMemo(()=>p?nN(t,r,p):null,[t,r,p]),R=H?t.filter(ue=>H.nodeIds.has(ue.id)):t,z=H?r.filter(ue=>H.edgeIds.has(ue.id)):r,ne=L.useMemo(()=>eN(R,z,{detail:M,families:Y,focusId:D,neighborhoodOnly:!!D}),[R,z,M,Y,D]),oe=L.useMemo(()=>`${$}|${ne.nodes.map(ue=>ue.id).join("\0")}|${ne.edges.map(ue=>ue.id).join("\0")}`,[$,ne.nodes,ne.edges]),fe=b?t.find(ue=>ue.id===b)??null:null,{rfNodes:he,rfEdges:pe}=L.useMemo(()=>{const ue=HN(ne.nodes,ne.edges,b,{roles:c,testOverlay:h,layout:$});return W&&(ue.rfEdges=ue.rfEdges.map(je=>({...je,animated:!1}))),ue},[ne.nodes,ne.edges,b,W,c,h,$]);L.useEffect(()=>{if(!s)return;const ue=t.find(je=>je.file_path===s);ue&&E(ue.id)},[s,t]);const Z=L.useMemo(()=>tN(t,te),[t,te]),se=(ue,je)=>{E(je.id)},me=()=>{E(null),J(!1)},Ne=fe?d.jsx(BN,{node:fe,nodes:t,edges:r,onClose:me,onWhatIf:o,onSelect:E,onOpenFile:v,pinned:g===fe.id,onPin:_,onIsolate:y?ue=>{y(p===ue?null:ue)}:void 0}):null,we=ue=>{q(je=>{const Le=new Set(je);if(Le.has(ue)){if(Le.size===1)return je;Le.delete(ue)}else Le.add(ue);return Le})},ve=L.useMemo(()=>{const ue=new Set;for(const je of t)ue.add(bm(je.type));return ue},[t]),Pe=t.length-ne.nodes.length;return d.jsxs("div",{className:"impact-graph",style:{flex:1,minHeight:0,position:"relative",display:"flex",flexDirection:"column"},children:[d.jsxs("div",{className:"graph-toolbar","data-testid":"graph-toolbar",children:[d.jsxs("div",{className:"seg","aria-label":"Graph projection",children:[d.jsx("button",{type:"button","data-testid":"graph-view-2d",className:U==="2d"?"active":"","aria-pressed":U==="2d",onClick:()=>w("2d"),children:"2D map"}),d.jsx("button",{type:"button","data-testid":"graph-view-3d",className:U==="3d"?"active":"","aria-pressed":U==="3d",onClick:()=>w("3d"),children:"3D layers"})]}),d.jsxs("div",{className:"seg","aria-label":"Graph detail",children:[d.jsx("button",{type:"button","data-testid":"graph-detail-overview",className:M==="overview"?"active":"","aria-pressed":M==="overview",onClick:()=>A("overview"),children:"Overview"}),d.jsx("button",{type:"button","data-testid":"graph-detail-full",className:M==="full"?"active":"","aria-pressed":M==="full",onClick:()=>A("full"),children:"Full"})]}),d.jsx("div",{className:"seg","aria-label":"Graph families",children:["django","stitch","react"].filter(ue=>ve.has(ue)).map(ue=>d.jsx("button",{type:"button","data-testid":`graph-family-${ue}`,className:Y.has(ue)?"active":"","aria-pressed":Y.has(ue),onClick:()=>we(ue),children:ue},ue))}),U==="2d"?d.jsxs("label",{className:"graph-layout",children:["Layout",d.jsx("select",{id:"graph-layout","data-testid":"graph-layout",value:$,"aria-label":"2D layout algorithm",onChange:ue=>{var Le;const je=(Le=xc.find(nt=>nt.id===ue.target.value))==null?void 0:Le.id;je&&(F(je),oN(je))},children:xc.map(ue=>d.jsx("option",{value:ue.id,children:ue.label},ue.id))})]}):null,d.jsx("button",{type:"button",className:re?"chip-btn active":"chip-btn","data-testid":"graph-neighborhood",disabled:!b,onClick:()=>J(ue=>!ue),children:re?"Neighborhood":"Focus neighbors"}),p?d.jsx("button",{type:"button",className:"chip-btn active","data-testid":"graph-isolate-clear",onClick:()=>y==null?void 0:y(null),children:"Path isolate"}):null,d.jsxs("label",{className:"graph-search",children:[d.jsx("span",{className:"sr-only",children:"Search nodes"}),d.jsx("input",{"data-testid":"graph-search",placeholder:"Find a node",value:te,onChange:ue=>{Q(ue.target.value),V(!0)},onFocus:()=>V(!0),onBlur:()=>window.setTimeout(()=>V(!1),150)}),C&&te.trim()&&Z.length?d.jsx("ul",{className:"graph-search-hits","data-testid":"graph-search-hits",children:Z.map(ue=>d.jsx("li",{children:d.jsxs("button",{type:"button",onMouseDown:je=>je.preventDefault(),onClick:()=>{E(ue.id),Q(""),V(!1)},children:[ue.name,d.jsx("span",{className:"muted",children:li(ue.type)})]})},ue.id))}):null]}),d.jsxs("span",{className:"muted graph-count",children:[ne.nodes.length," nodes · ",ne.edges.length," edges",Pe?` · ${Pe} hidden`:""]})]}),d.jsx("div",{className:"graph-stage",children:t.length===0?d.jsxs("div",{className:"empty graph-walk-empty","data-testid":"graph-walk-empty",children:[d.jsx("h2",{children:"No typed nodes on this walk"}),d.jsx("p",{children:"This range did not hit models, views, routes, or React pages Loadpath extracts. Open the architecture map for the indexed graph."})]}):U==="3d"?d.jsxs("div",{className:"graph-3d","data-testid":"graph-3d",children:[d.jsx("p",{className:"graph-3d-hint",children:"Architecture layers are stacked in depth (Django → stitch → React). Drag to orbit, scroll to zoom, click a node to inspect it."}),d.jsx(L.Suspense,{fallback:d.jsx("p",{className:"muted graph-3d-hint",children:"Loading 3D layers…"}),children:d.jsx(RN,{nodes:ne.nodes,edges:ne.edges,selectedId:b,neighborIds:D?ne.neighborIds:IN,onSelect:ue=>{E(ue),ue||J(!1)}})}),Ne]}):d.jsxs(vm,{children:[d.jsxs(dk,{nodes:he,edges:pe,nodeTypes:$N,edgeTypes:ON,fitView:!1,minZoom:.25,nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,deleteKeyCode:null,onNodeClick:se,onPaneClick:me,proOptions:{hideAttribution:!1},"data-testid":"impact-graph",children:[d.jsx(FN,{topologyKey:oe}),d.jsx(mk,{}),d.jsx(zk,{pannable:!0,zoomable:!0,ariaLabel:"Impact graph overview",nodeColor:"var(--muted)",nodeStrokeColor:"transparent",nodeStrokeWidth:0,maskColor:"rgba(0, 0, 0, 0.45)",maskStrokeColor:"var(--accent)",maskStrokeWidth:1.4,bgColor:"var(--graph-bg)",style:{width:184,height:128}}),d.jsx(kk,{})]}),Ne]})})]})}function Em(){const t=localStorage.getItem("loadpath.editor")||"auto";return t==="cursor"||t==="vscode"||t==="system"?t:"auto"}function VN(t){localStorage.setItem("loadpath.editor",t)}async function WN(t,r,o,s=Em()){try{const a=await Te.openEditor(t,r,o??void 0,s);if(a.ok)return{ok:!0,message:`Opened ${r} in ${a.opened_with||"editor"}`};const u=a.urls||{},c=s==="vscode"?u.vscode:s==="cursor"?u.cursor:u.cursor||u.vscode;return c?(window.open(c,"_blank","noopener,noreferrer"),{ok:!0,message:`Opening ${r} via editor URL`}):{ok:!1,message:a.error||"Could not open editor"}}catch(a){return{ok:!1,message:a instanceof Error?a.message:String(a)}}}const Cp=[{value:"HEAD",label:"HEAD",group:"preset"},{value:"HEAD~1",label:"HEAD~1",group:"preset"}],UN=["preset","branch","tag","commit"];function GN(t){var a;if(!(t!=null&&t.git))return[...Cp];const r=((a=t.presets)!=null&&a.length?t.presets:Cp.map(u=>u.value)).map(u=>({value:u,label:u,group:"preset"})),o=new Set(r.map(u=>u.value)),s=[...r];for(const u of t.branches||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.current?`${u.name} (current)`:u.name,detail:u.subject,group:"branch"}));for(const u of t.tags||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.name,detail:u.subject,group:"tag"}));for(const u of t.commits||[])o.has(u.sha)||(o.add(u.sha),s.push({value:u.sha,label:u.short,detail:u.subject,group:"commit"}));return s}function YN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>s.value.toLowerCase().includes(o)||s.label.toLowerCase().includes(o)||(s.detail||"").toLowerCase().includes(o)):t}function XN(t){return UN.map(r=>({group:r,items:t.filter(o=>o.group===r)})).filter(r=>r.items.length>0)}function qN(t){return t==="preset"?"Common":t==="branch"?"Branches":t==="tag"?"Tags":"Recent commits"}function Mp({value:t,onChange:r,placeholder:o,testId:s,menuTestId:a,refs:u,onNeedRefs:c}){const h=L.useId(),p=L.useRef(null),[y,x]=L.useState(!1),[v,g]=L.useState(null),[_,S]=L.useState(0),N=L.useMemo(()=>{const j=GN(u);return v===null?j:YN(j,v)},[u,v]),b=L.useMemo(()=>XN(N),[N]);L.useEffect(()=>{y&&c()},[y,c]),L.useEffect(()=>{S(0)},[v,y]);const E=()=>{x(!1),g(null)},I=j=>{r(j.value),E()},w=j=>{if(j.key==="ArrowDown"){if(j.preventDefault(),!y){x(!0);return}S(A=>Math.min(A+1,Math.max(N.length-1,0)))}else if(j.key==="ArrowUp"){if(j.preventDefault(),!y)return;S(A=>Math.max(A-1,0))}else if(j.key==="Enter"&&y){j.preventDefault();const A=N[_];A&&I(A)}else j.key==="Escape"&&y&&(j.preventDefault(),E())};return d.jsxs("div",{className:"combo",ref:p,onBlur:j=>{j.currentTarget.contains(j.relatedTarget)||E()},children:[d.jsxs("div",{className:"combo-row",children:[d.jsx("input",{"data-testid":s,value:t,placeholder:o,spellCheck:!1,role:"combobox","aria-expanded":y,"aria-controls":h,"aria-autocomplete":"list",onChange:j=>{r(j.target.value),y&&g(j.target.value)},onKeyDown:w}),d.jsx("button",{type:"button",className:"icon-btn combo-toggle","data-testid":`${s}-toggle`,"aria-label":"Show recent refs","aria-expanded":y,onMouseDown:j=>j.preventDefault(),onClick:()=>y?E():x(!0),children:d.jsx(C0,{})})]}),y?d.jsx("div",{className:"combo-menu",id:h,role:"listbox","data-testid":a,children:b.length===0?d.jsx("div",{className:"combo-empty muted",children:"No matching refs — the typed value is kept"}):b.map(j=>d.jsxs("div",{className:"combo-group",children:[d.jsx("div",{className:"combo-heading",children:qN(j.group)}),j.items.map(A=>{const $=N.indexOf(A);return d.jsxs("button",{type:"button",role:"option","aria-selected":$===_,className:$===_?"combo-option active":"combo-option","data-testid":`ref-option-${A.group}`,onMouseDown:F=>F.preventDefault(),onMouseEnter:()=>S($),onClick:()=>I(A),children:[d.jsx("span",{className:"combo-label",children:A.label}),A.detail?d.jsx("span",{className:"combo-detail",children:A.detail}):null]},`${A.group}:${A.value}`)})]},j.group))}):null]})}function KN({initialPath:t,onSelect:r,onClose:o}){const[s,a]=L.useState(null),[u,c]=L.useState(t),[h,p]=L.useState(null),[y,x]=L.useState(""),[v,g]=L.useState(!1),_=L.useRef(null),S=L.useRef(0),N=async w=>{const j=S.current+1;S.current=j,g(!0);try{const A=await Te.browse(w);if(S.current!==j)return;a(A),c(A.path),p(A.is_git?A.path:null),x("")}catch(A){if(S.current!==j)return;x(A instanceof Error?A.message:String(A))}finally{S.current===j&&g(!1)}};L.useEffect(()=>{var w,j;N(t),(w=_.current)==null||w.focus(),(j=_.current)==null||j.select()},[t]);const b=h||(s==null?void 0:s.path)||u,E=h&&h!==(s==null?void 0:s.path)?h.split(/[\\/]/).filter(Boolean).pop():s!=null&&s.is_git?"this repository":"this folder",I=w=>{w.key==="Escape"&&(w.preventDefault(),o())};return d.jsx("div",{className:"modal-backdrop","data-testid":"repo-explorer","data-overlay":"true",onClick:o,onKeyDown:I,children:d.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"explorer-title",onClick:w=>w.stopPropagation(),children:[d.jsxs("div",{className:"modal-head",children:[d.jsxs("div",{children:[d.jsx("h2",{id:"explorer-title",children:"Select repository"}),d.jsx("p",{className:"muted",children:"Browse to a git root, or paste the full path."})]}),d.jsx("button",{type:"button",className:"btn ghost","data-testid":"explorer-cancel",onClick:o,children:"Cancel"})]}),d.jsxs("form",{className:"explorer-path",onSubmit:w=>{w.preventDefault(),N(u)},children:[d.jsx("input",{ref:_,"data-testid":"explorer-path",value:u,onChange:w=>c(w.target.value),spellCheck:!1,"aria-label":"Directory path"}),d.jsx("button",{type:"button",className:"btn",disabled:!(s!=null&&s.parent),onClick:()=>(s==null?void 0:s.parent)&&void N(s.parent),children:"Up"}),d.jsx("button",{type:"button",className:"btn",onClick:()=>s&&void N(s.home),children:"Home"}),d.jsx("button",{type:"submit",className:"btn",children:"Go"})]}),y?d.jsx("div",{className:"error",role:"alert",children:y}):null,d.jsx("div",{className:"explorer-list",role:"listbox","aria-label":"Folders","aria-busy":v,children:s!=null&&s.entries.length?s.entries.map(w=>{const j=h===w.path;return d.jsxs("button",{type:"button",role:"option","aria-selected":j,className:j?"explorer-row active":"explorer-row","data-testid":"explorer-entry","data-path":w.path,onClick:()=>p(w.path),onDoubleClick:()=>void N(w.path),children:[d.jsx(Tp,{}),d.jsx("span",{className:"explorer-name",children:w.name}),w.is_git?d.jsx("span",{className:"chip git-badge",children:"git"}):null]},w.path)}):d.jsx("div",{className:"muted explorer-empty",children:v?"Loading…":"No folders here"})}),d.jsxs("div",{className:"modal-foot",children:[d.jsx("span",{className:"muted explorer-current",title:b,children:b}),d.jsxs("button",{type:"button",className:"btn primary","data-testid":"explorer-use",disabled:!b,onClick:()=>b&&r(b),children:["Use ",E]})]})]})})}const QN={scan:{start:0,end:20},extract:{start:20,end:88},boot:{start:88,end:94},stitch:{start:94,end:99},skipped:{start:100,end:100},done:{start:100,end:100}},ZN=new Set(["scan","extract","boot","stitch"]);function JN(t){const r=t.phase||"";if(!r||r==="idle")return null;const o=QN[r];if(!o)return null;if(o.start===o.end)return o.end;const s=t.total||0;if(s<=0)return o.start;const a=Math.min(1,Math.max(0,(t.done||0)/s));return Math.round(o.start+(o.end-o.start)*a)}function ej(t){return!t.phase||t.phase==="idle"?null:typeof t.percent=="number"&&Number.isFinite(t.percent)?Math.max(0,Math.min(100,Math.round(t.percent))):JN(t)}const Qa=[{id:"obsidian",label:"Obsidian",group:"dark"},{id:"nord",label:"Nord",group:"dark"},{id:"solarized-dark",label:"Solarized Dark",group:"dark"},{id:"forest",label:"Forest",group:"dark"},{id:"rose",label:"Rose Pine",group:"dark"},{id:"amber",label:"Midnight Amber",group:"dark"},{id:"volcano",label:"Volcano",group:"dark"},{id:"lavender",label:"Lavender",group:"dark"},{id:"neon-noir",label:"Neon Noir",group:"dark"},{id:"synthwave",label:"Synthwave",group:"dark"},{id:"phosphor",label:"Phosphor",group:"dark"},{id:"aurora",label:"Aurora",group:"dark"},{id:"biolume",label:"Biolume",group:"dark"},{id:"carbon",label:"Carbon",group:"dark"},{id:"paper",label:"Paper",group:"light"},{id:"solarized-light",label:"Solarized Light",group:"light"},{id:"seafoam",label:"Seafoam",group:"light"},{id:"high-contrast",label:"High Contrast",group:"light"},{id:"sakura",label:"Sakura",group:"light"},{id:"citrus",label:"Citrus",group:"light"},{id:"peach",label:"Peach Fuzz",group:"light"},{id:"candy",label:"Cotton Candy",group:"light"},{id:"sky",label:"Clear Sky",group:"light"},{id:"coral",label:"Coral Reef",group:"light"}],tj="obsidian",Cm="loadpath.theme";function nj(t){return Qa.some(r=>r.id===t)}function Mm(){try{const t=localStorage.getItem(Cm)||"";if(nj(t))return t}catch{}return tj}function rj(t){var r;return((r=Qa.find(o=>o.id===t))==null?void 0:r.group)==="light"?"light":"dark"}function Pm(t){document.documentElement.dataset.theme=t,document.documentElement.style.colorScheme=rj(t);try{localStorage.setItem(Cm,t)}catch{}}const rc=[{id:"review",label:"Review",testId:"tab-review",shortcut:"1",icon:k0},{id:"architecture",label:"Architecture",testId:"tab-architecture",shortcut:"2",icon:N0},{id:"graph",label:"Impact graph",testId:"tab-graph",shortcut:"3",icon:j0},{id:"prs",label:"Pull requests",testId:"tab-prs",shortcut:"4",icon:b0},{id:"settings",label:"Settings",testId:"tab-settings",shortcut:"5",icon:E0}];function oc(t,r,o){let s;try{s=new URL(t)}catch{return}if(s.protocol!=="https:"||s.username||s.password)return;const a=s.hostname.toLowerCase();a!==r&&!a.endsWith(`.${r}`)||s.pathname.startsWith(o)&&window.open(s.toString(),"_blank","noopener,noreferrer")}function oj(){var gi,jo,mi,yi,vi,bo,Xr,an,ln,un;const[t,r]=L.useState("review"),[o,s]=L.useState(localStorage.getItem("loadpath.repo")||""),[a,u]=L.useState(localStorage.getItem("loadpath.base")||"HEAD~1"),[c,h]=L.useState(localStorage.getItem("loadpath.head")||"HEAD"),[p,y]=L.useState(null),[x,v]=L.useState(null),[g,_]=L.useState(null),[S,N]=L.useState([]),[b,E]=L.useState("review"),[I,w]=L.useState(""),[j,A]=L.useState(""),[$,F]=L.useState(null),[Y,q]=L.useState(!1),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState({}),[W,U]=L.useState([]),[M,D]=L.useState([]),[H,R]=L.useState(localStorage.getItem("loadpath.scmRepo")||""),[z,ne]=L.useState(localStorage.getItem("loadpath.provider")||"github"),[oe,fe]=L.useState(localStorage.getItem("loadpath.prNumber")||""),[he,pe]=L.useState(localStorage.getItem("loadpath.dirty")==="1"),[Z,se]=L.useState(0),[me,Ne]=L.useState(""),[we,ve]=L.useState(Mm),[Pe,ue]=L.useState(!1),[je,Le]=L.useState(!1),[nt,lt]=L.useState(!1),[ut,Ye]=L.useState(null),[wt,Yt]=L.useState(null),[gt,mt]=L.useState(localStorage.getItem("loadpath.testOverlay")==="1"),[Ct,ct]=L.useState(null),[et,On]=L.useState(localStorage.getItem("loadpath.watch")==="1"),[Mt,kn]=L.useState([]),[ui,Fn]=L.useState(null),[vo,lr]=L.useState(null),[Or,Hn]=L.useState(null),[Fr,ur]=L.useState(()=>{try{return!!(localStorage.getItem("loadpath.lastReviewId")&&(localStorage.getItem("loadpath.repo")||"").trim())}catch{return!1}}),[cr,Ft]=L.useState(null),[dt,Bn]=L.useState(null),[Vn,Nn]=L.useState(!1),[Wn,jn]=L.useState(!1),it=L.useRef(o);it.current=o;const dr=L.useRef(he);dr.current=he;const bn=L.useRef(!1);bn.current=je;const Pt=L.useRef(""),nn=L.useRef(""),xo=P=>{ve(P),Pm(P)},Ze=L.useRef(""),He=P=>{Ze.current=P,A(P)},En=P=>{let G=0,ce=!1;F(0);const Ce=()=>{Te.indexProgress(P).then(Re=>{if(!Ze.current)return;if(Re.phase&&Re.phase!=="idle"&&Re.message&&He(Re.message),ZN.has(Re.phase))ce=!0;else if(!ce)return;const mr=ej(Re);mr!=null&&(Re.phase==="scan"&&!Re.done?G=mr:G=Math.max(G,mr),F(G))}).catch(()=>{})};Ce();const Ie=window.setInterval(Ce,250);return()=>{window.clearInterval(Ie),F(null)}};L.useEffect(()=>{Te.settings().then(V).catch(()=>{}).finally(()=>ue(!0)),Te.repos().then(P=>N(P.repos)).catch(()=>{})},[]);const Un=()=>o.trim()?!0:(w("Point at a local repository path first."),!1);L.useEffect(()=>{if(t!=="architecture"||!o.trim())return;const P=o;let G=!1;return nn.current!==P&&Yn(P),Te.config(P).then(ce=>{!G&&it.current===P&&lr(ce)}).catch(()=>{}),Te.architectureHealth(P).then(ce=>{!G&&it.current===P&&Hn(ce)}).catch(()=>{}),()=>{G=!0}},[t,o]);const rn=P=>{it.current=P,s(P),localStorage.setItem("loadpath.repo",P),P.trim()!==Pt.current&&(Pt.current="",Ft(null))},Hr=L.useCallback(P=>{const G=(P??it.current).trim();return!G||Pt.current===G?Promise.resolve():(Pt.current=G,Te.gitRefs(G).then(ce=>{it.current.trim()===G&&Ft(ce)}).catch(()=>{Pt.current===G&&(Pt.current="",Ft(null))}))},[]),on=(P,G)=>{u(P),h(G),localStorage.setItem("loadpath.base",P),localStorage.setItem("loadpath.head",G)},It=(P,G,ce)=>{ne(P),R(G),localStorage.setItem("loadpath.provider",P),localStorage.setItem("loadpath.scmRepo",G),ce!==void 0&&(fe(ce),localStorage.setItem("loadpath.prNumber",ce))},Xt=P=>{y(P),se(0),Ye(wt&&P.nodes.some(G=>G.id===wt)?wt:null),ct(null),Fn(null),P.what_if||(v(P),P.id&&localStorage.setItem("loadpath.lastReviewId",P.id))},Gn=async P=>{try{const G=await Te.reviews(P);kn(G.reviews)}catch{kn([])}},wo=async P=>{try{Hn(await Te.architectureHealth(P))}catch{Hn(null)}},_o=P=>P==="github"?!!C.github_token_set:P==="gitlab"?!!C.gitlab_token_set:!!C.bitbucket_token_set,Rt=L.useCallback(async(P=z)=>{var G;try{const ce=await Te.scmRepos(P);D(ce.repos),(G=ce.user)!=null&&G.login&&V(Ce=>({...Ce,...P==="github"?{github_user:ce.user.login}:P==="gitlab"?{gitlab_user:ce.user.login}:{bitbucket_user:ce.user.login}}))}catch{D([])}},[z]);L.useEffect(()=>{if(t!=="prs")return;let P=!1;return Rt(z).catch(()=>{P||D([])}),()=>{P=!0}},[t,z,Rt]),L.useEffect(()=>{if(!dt)return;let P=!1,G=0;const ce=async()=>{try{const Ce=await Te.githubOAuthPoll(dt.flow_id);if(P)return;if(Ce.status==="complete"){Bn(null);const Ie=await Te.settings();V(Ie),Q(Ce.user?`Signed in to GitHub as ${Ce.user}`:"Signed in to GitHub"),Rt("github");return}if(Ce.status==="pending"||Ce.status==="slow_down"){G=window.setTimeout(ce,Math.max(Ce.interval||dt.interval,5)*1e3);return}Bn(null),w(Ce.status==="denied"?"GitHub sign-in was denied.":"GitHub sign-in expired. Try again.")}catch(Ce){if(P)return;Bn(null),w(Ce instanceof Error?Ce.message:String(Ce))}};return G=window.setTimeout(ce,Math.max(dt.interval,5)*1e3),()=>{P=!0,window.clearTimeout(G)}},[dt,Rt]),L.useEffect(()=>{if(!Vn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.bitbucket.connected){Nn(!1);const Re=await Te.settings();V(Re),Q(Ie.bitbucket.user?`Signed in to Bitbucket as ${Ie.bitbucket.user}`:"Signed in to Bitbucket"),Rt("bitbucket");return}if(Date.now()-ce>18e4){Nn(!1),w("Bitbucket sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;Nn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Vn,Rt]),L.useEffect(()=>{if(!Wn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.gitlab.connected){jn(!1);const Re=await Te.settings();V(Re),Q(Ie.gitlab.user?`Signed in to GitLab as ${Ie.gitlab.user}`:"Signed in to GitLab"),Rt("gitlab");return}if(Date.now()-ce>18e4){jn(!1),w("GitLab sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;jn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Wn,Rt]);const Yn=async(P=o,G=!1)=>{if(!P.trim())return null;nn.current=P,J(!0);try{const ce=await Te.architecture(P,!1);it.current===P&&_(ce);const Ce=Te.architectureGraph(P).then(Ie=>{it.current===P&&_(Re=>Re&&{...Re,nodes:Ie.nodes,edges:Ie.edges,graph_pending:!1})});return Ce.catch(()=>{_(Ie=>Ie&&it.current===P?{...Ie,graph_pending:!1}:Ie)}).finally(()=>{nn.current===P&&J(!1)}),G&&await Ce,ce}catch(ce){throw it.current===P&&J(!1),ce}},Br=async P=>{const G=P.trim();if(!(!G||G===it.current)){if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}w(""),Q(""),y(null),v(null),_(null),E("architecture"),rn(G),q(!0),He(`Loading ${S0(G)}…`);try{await Promise.all([Yn(G),Hr(G)])}catch(ce){it.current===G&&w(ce instanceof Error?ce.message:String(ce))}finally{it.current===G&&(He(""),q(!1))}}},Xn=async()=>{if(Ze.current||!Un())return;w(""),Q(""),He("Tracing load path…"),rn(o),on(a,c);const P=En(o);try{const G=await Te.review(o,a,c,!0,dr.current);Xt(G),E("review"),r("review"),await Te.repos().then(ce=>N(ce.repos)).catch(()=>{}),await Promise.all([Yn(o),Gn(o),wo(o)])}catch(G){w(G instanceof Error?G.message:String(G))}finally{P(),He("")}},fr=async(P=!0)=>{if(Ze.current||!Un())return;w(""),Q(""),He(P?"Indexing…":"Full reindex…"),rn(o);const G=En(o);try{await Te.index(o,P);const ce=await Yn(o);await Te.repos().then(Ce=>N(Ce.repos)).catch(()=>{}),ce!=null&&ce.indexed&&(E("architecture"),r("architecture"))}catch(ce){w(ce instanceof Error?ce.message:String(ce))}finally{G(),He("")}},Ve=async()=>{if(!Ze.current&&Un()){w(""),Q(""),He("Detecting layout…"),rn(o);try{const P=await Te.init(o);Q(P.message),await Te.repos().then(G=>N(G.repos)).catch(()=>{})}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},ci=async()=>{if(p!=null&&p.markdown)try{await navigator.clipboard.writeText(p.markdown),Q("Copied markdown brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Vr=async()=>{if(!Ze.current){if(p!=null&&p.what_if){w("What-if walks are hypothetical — they are not posted to a pull request. Restore the git-range walk first.");return}if(!(p!=null&&p.markdown)||!H||!oe){w("Pick a pull request first (Pull requests tab), then post the brief.");return}He("Posting Loadpath brief…");try{const P=await Te.postComment(z,H,Number(oe),p.markdown);Q(P.updated?"Updated the Loadpath PR comment":"Posted the Loadpath PR comment")}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},So=async()=>{if(!Ze.current){w(""),He("Fetching pull requests…");try{const P=await Te.prs(z,H,"open",o.trim()||void 0);U(P.pull_requests);const G=M.find(ce=>ce.slug.toLowerCase()===H.trim().toLowerCase());G!=null&&G.local_path&&rn(G.local_path)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},hr=async()=>{w("");try{const P=await Te.githubOAuthStart();Bn(P),oc(P.verification_uri_complete,"github.com","/login/device")}catch(P){w(P instanceof Error?P.message:String(P))}},di=async()=>{w("");try{const P=await Te.bitbucketOAuthStart();Nn(!0),oc(P.authorize_url,"bitbucket.org","/site/oauth2/authorize")}catch(P){Nn(!1),w(P instanceof Error?P.message:String(P))}},ko=async()=>{w("");try{const P=await Te.gitlabOAuthStart();jn(!0),oc(P.authorize_url,new URL(P.authorize_url).hostname,"/oauth/authorize")}catch(P){jn(!1),w(P instanceof Error?P.message:String(P))}},Cn=async P=>{if(!(Ze.current||!o.trim())){w(""),He("Walking what-if path…");try{const G=await Te.whatIf(o,P);Q(`${G.title} — ${G.confidence.level} · ${(G.sinks||[]).length} sinks`),Xt({...G,markdown:G.markdown||"",index:G.index||(p==null?void 0:p.index),workspace:G.workspace||(p==null?void 0:p.workspace)}),E("review"),r("review")}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},_t=()=>{if(x){Xt(x),E("review"),r("review"),Q("Restored the last git-range walk");return}y(null),se(0),Ye(null),ct(null),Fn(null),E("architecture"),r("architecture"),Q("")},fi=async P=>{var Ie;if(Ze.current)return;It(P.provider,P.repo,String(P.number));const G=M.find(Re=>Re.slug.toLowerCase()===P.repo.toLowerCase());G!=null&&G.local_path&&rn(G.local_path),w(""),He(`Fetching ${P.provider} #${P.number}…`);const ce=(G==null?void 0:G.local_path)||o,Ce=ce?En(ce):()=>{};try{const Re=await Te.reviewPr(P.provider,P.repo,P.number,(G==null?void 0:G.local_path)||o||void 0);Xt(Re),Re.pull_request&&typeof Re.pull_request.repo_path=="string"&&rn(Re.pull_request.repo_path),on(String(Re.base||P.target_branch),String(Re.head||P.source_branch)),E("review"),r("review"),typeof((Ie=Re.pull_request)==null?void 0:Ie.repo_path)=="string"&&Gn(Re.pull_request.repo_path)}catch(Re){on(P.base_sha||P.target_branch,P.head_sha||P.source_branch),r("review"),w(Re instanceof Error?Re.message:String(Re))}finally{Ce(),He("")}},yt=async P=>{w("");try{V(await Te.oauthDisconnect(P)),z===P&&D([]),Q(`Disconnected ${P}`)}catch(G){w(G instanceof Error?G.message:String(G))}},hi=async P=>{P.preventDefault();const G=new FormData(P.currentTarget),ce={github_token:String(G.get("github_token")||""),github_oauth_client_id:String(G.get("github_oauth_client_id")||""),github_host:String(G.get("github_host")||""),gitlab_token:String(G.get("gitlab_token")||""),gitlab_host:String(G.get("gitlab_host")||""),gitlab_oauth_client_id:String(G.get("gitlab_oauth_client_id")||""),gitlab_oauth_client_secret:String(G.get("gitlab_oauth_client_secret")||""),bitbucket_token:String(G.get("bitbucket_token")||""),bitbucket_username:String(G.get("bitbucket_username")||""),bitbucket_oauth_client_id:String(G.get("bitbucket_oauth_client_id")||""),bitbucket_oauth_client_secret:String(G.get("bitbucket_oauth_client_secret")||""),ai_provider:String(G.get("ai_provider")||"none"),ai_api_key:String(G.get("ai_api_key")||""),ai_model:String(G.get("ai_model")||""),ai_base_url:String(G.get("ai_base_url")||"")},Ce=S.length?{...ce,workspaces:S.map(Ie=>({path:Ie.path,name:Ie.name}))}:ce;try{V(await Te.saveSettings(Ce)),Q("Settings saved on this machine")}catch(Ie){w(Ie instanceof Error?Ie.message:String(Ie))}},pi=async()=>{if(!(!p||Ze.current)){He("Residual analysis…");try{const P=await Te.residual(p);Ne(P.note)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},Wr=L.useRef(Xn);Wr.current=Xn;const Mn=L.useRef(t);Mn.current=t;const qn=L.useRef(!1);qn.current=nt;const Pn=L.useRef(p);Pn.current=p;const qt=L.useRef(Z);qt.current=Z,L.useEffect(()=>{const P=localStorage.getItem("loadpath.lastReviewId"),G=(localStorage.getItem("loadpath.repo")||"").trim();if(!P||!G){ur(!1);return}let ce=!1;return Te.getReview(G,P).then(Ce=>{ce||(Xt(Ce),on(Ce.base||localStorage.getItem("loadpath.base")||"HEAD~1",Ce.head||localStorage.getItem("loadpath.head")||"HEAD"),Gn(G),wo(G))}).catch(()=>{}).finally(()=>{ce||ur(!1)}),()=>{ce=!0}},[]);const Ur=L.useRef("");L.useEffect(()=>{if(!et||!o.trim())return;let P=!1;const G=async()=>{try{const Ce=await Te.workspaceStatus(o);if(P)return;Ur.current&&Ce.fingerprint!==Ur.current&&!Ze.current&&(pe(!0),dr.current=!0,localStorage.setItem("loadpath.dirty","1"),Wr.current()),Ur.current=Ce.fingerprint}catch{}};G();const ce=window.setInterval(G,2e3);return()=>{P=!0,window.clearInterval(ce)}},[et,o]),L.useEffect(()=>{const P=G=>{var Ie;if((G.metaKey||G.ctrlKey)&&G.key.toLowerCase()==="k"){G.preventDefault(),lt(Re=>!Re);return}if(qn.current){G.key==="Escape"&&(G.preventDefault(),lt(!1));return}if(bn.current){G.key==="Escape"&&(G.preventDefault(),Le(!1));return}const ce=G.target;if(ce&&(ce.tagName==="INPUT"||ce.tagName==="TEXTAREA"||ce.tagName==="SELECT"||ce.isContentEditable)){G.key==="Escape"&&ce.blur();return}if(G.key==="Escape"){w(""),Q(""),Ye(wt),ct(null);return}if(G.key==="j"||G.key==="k"){const Re=((Ie=Pn.current)==null?void 0:Ie.read_order)||[];if(!Re.length)return;G.preventDefault();const xi=qt.current,mr=G.key==="j"?Math.min(Re.length-1,xi+1):Math.max(0,xi-1);se(mr);return}const Ce=rc.find(Re=>Re.shortcut===G.key);if(Ce&&!G.metaKey&&!G.ctrlKey&&!G.altKey&&r(Ce.id),(G.metaKey||G.ctrlKey)&&G.key==="Enter"){if(Mn.current==="settings"||Mn.current==="prs"||Ze.current)return;G.preventDefault(),Wr.current()}};return window.addEventListener("keydown",P),()=>window.removeEventListener("keydown",P)},[wt]);const Gr=async(P,G)=>{if(!o.trim())return;const ce=await WN(o,P,G);ce.ok?Q(ce.message):w(ce.message)},pr=async()=>{if(p)try{const P=await Te.exportHtml(p),G=URL.createObjectURL(P),ce=document.createElement("a");ce.href=G,ce.download=`loadpath-${(p.id||"review").slice(0,8)}.html`,ce.click(),URL.revokeObjectURL(G),Q("Saved HTML brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Yr=async P=>{if(o.trim()){He("Loading stored review…");try{const G=await Te.getReview(o,P);Xt(G),on(G.base||a,G.head||c),E("review"),r("review");const ce=Mt.findIndex(Ie=>Ie.id===P),Ce=ce>=0?Mt[ce+1]:void 0;if(Ce)try{Fn(await Te.reviewDiff(o,P,Ce.id))}catch{Fn(null)}}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},sn={selectedId:ut,onSelect:Ye,nodeRoles:p==null?void 0:p.node_roles,testOverlay:gt,isolateSource:Ct,onIsolate:ct,repoPath:o,onOpenFile:Gr,pinnedId:wt,onPin:Yt},Kn=[{id:"review",group:"Run",label:"Review this range",hint:"⌘/Ctrl+Enter",run:()=>void Xn()},...p!=null&&p.what_if?[{id:"exit-whatif",group:"Review",label:x?"Back to git-range walk":"Exit what-if walk",run:_t}]:[],{id:"index",group:"Run",label:"Index repository",run:()=>void fr(!0)},{id:"watch",group:"Run",label:et?"Stop watching working tree":"Watch working tree",run:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")}},{id:"tests",group:"Graph",label:gt?"Hide test overlay":"Show test overlay",run:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")}},{id:"export",group:"Review",label:"Export HTML brief",run:()=>void pr()},...rc.map(P=>({id:`tab-${P.id}`,group:"Tabs",label:`Go to ${P.label}`,hint:P.shortcut,run:()=>r(P.id)})),...((p==null?void 0:p.nodes)||[]).slice(0,30).map(P=>({id:`node-${P.id}`,group:"Nodes",label:P.name,hint:li(P.type),run:()=>{Ye(P.id),r("graph")}})),...Mt.slice(0,12).map(P=>({id:`hist-${P.id}`,group:"History",label:P.title||P.id,hint:`${P.level||""} ${P.created_at||""}`.trim(),run:()=>void Yr(P.id)}))],No=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.nodes)??[]:(p==null?void 0:p.nodes)??[],[b,g,p]),gr=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.edges)??[]:(p==null?void 0:p.edges)??[],[b,g,p]),Fe=p!=null&&p.index?`${p.index.counts.nodes} nodes · ${p.index.counts.edges} edges`:g!=null&&g.indexed?`${g.counts.nodes} nodes · ${g.counts.edges} edges`:"Not indexed",_s=((p==null?void 0:p.findings)||[]).filter(P=>!P.waived);return d.jsxs("div",{className:"app",children:[d.jsx("a",{className:"skip",href:"#main",children:"Skip to content"}),d.jsxs("nav",{className:"rail","data-testid":"rail","aria-label":"Primary",children:[d.jsxs("div",{className:"brand",children:[d.jsx("div",{className:"brand-mark",children:"Loadpath"}),d.jsx("div",{className:"brand-sub",children:"Load-path review"})]}),rc.map(P=>{const G=P.icon,ce=t===P.id;return d.jsxs("button",{type:"button","data-testid":P.testId,className:ce?"nav-item active":"nav-item","aria-current":ce?"page":void 0,"aria-label":P.label,onClick:()=>r(P.id),children:[d.jsx(G,{}),d.jsx("span",{children:P.label})]},P.id)}),d.jsxs("div",{className:"theme-pick",children:[d.jsx("label",{htmlFor:"theme-select",children:"Theme"}),d.jsx("select",{id:"theme-select","data-testid":"theme-select",value:we,onChange:P=>xo(P.target.value),children:["dark","light"].map(P=>d.jsx("optgroup",{label:P==="dark"?"Dark":"Light",children:Qa.filter(G=>G.group===P).map(G=>d.jsx("option",{value:G.id,children:G.label},G.id))},P))})]}),d.jsxs("div",{className:"rail-foot",children:[d.jsx("div",{className:"muted",role:"status",children:j||Fe}),d.jsxs("div",{className:"kbd-hint",children:[d.jsx("kbd",{children:"1"}),"–",d.jsx("kbd",{children:"5"})," tabs · ",d.jsx("kbd",{children:"⌘"}),d.jsx("kbd",{children:"K"})," palette · ",d.jsx("kbd",{children:"j"}),"/",d.jsx("kbd",{children:"k"})," read order"]})]})]}),d.jsxs("div",{className:"main",id:"main",children:[j?d.jsxs("div",{className:$!=null?"progress determinate":"progress",role:$!=null?"progressbar":"status","aria-label":j,"aria-live":"polite","aria-busy":"true","aria-valuemin":$!=null?0:void 0,"aria-valuemax":$!=null?100:void 0,"aria-valuenow":$??void 0,"data-testid":"progress",children:[d.jsx("i",{style:$!=null?{width:`${$}%`}:void 0}),d.jsx("span",{className:"sr-only",children:j})]}):null,d.jsxs("header",{className:"topbar","data-testid":"topbar",children:[S.length>0?d.jsxs("label",{className:"field workspace",children:[d.jsx("span",{children:"Workspace"}),d.jsxs("select",{"data-testid":"workspace-select",value:S.some(P=>P.path===o)?o:"",disabled:!!j,"aria-busy":Y,onChange:P=>{P.target.value&&Br(P.target.value)},children:[d.jsx("option",{value:"",children:"Indexed repos…"}),S.map(P=>d.jsxs("option",{value:P.path,children:[P.name,P.indexed?` (${P.counts.nodes})`:""]},P.path))]})]}):null,d.jsxs("label",{className:"field path",children:[d.jsx("span",{children:"Repository"}),d.jsxs("div",{className:"path-row",children:[d.jsx("input",{"data-testid":"repo-path",placeholder:"Local monorepo path",value:o,onChange:P=>{const G=P.target.value;s(G),G.trim()!==Pt.current&&(Pt.current="",Ft(null))},spellCheck:!1}),d.jsx("button",{type:"button",className:"icon-btn","data-testid":"btn-browse-repo","aria-label":"Browse for a local repository",onClick:()=>Le(!0),children:d.jsx(Tp,{})})]})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Base"}),d.jsx(Mp,{testId:"base-ref",menuTestId:"base-ref-menu",value:a,onChange:P=>on(P,c),placeholder:"base",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Head"}),d.jsx(Mp,{testId:"head-ref",menuTestId:"head-ref-menu",value:c,onChange:P=>on(a,P),placeholder:"head",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Working tree"}),d.jsx("button",{type:"button",className:he?"chip-btn active":"chip-btn","data-testid":"btn-dirty","aria-pressed":he,onClick:()=>{const P=!he;pe(P),localStorage.setItem("loadpath.dirty",P?"1":"0")},children:he?"Include uncommitted":"Committed range"})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Watch"}),d.jsx("button",{type:"button",className:et?"chip-btn active":"chip-btn","data-testid":"btn-watch","aria-pressed":et,onClick:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")},children:et?"Watching":"Paused"})]}),p?d.jsxs("div",{className:`merge-box compact ${p.confidence.level}`,"data-testid":"merge-box",children:[d.jsx("div",{className:`level ${p.confidence.level}`,children:p.confidence.level.toUpperCase()}),d.jsxs("div",{className:"muted",children:[p.what_if?"what-if · ":"",p.confidence.covered_sinks,"/",p.confidence.sinks," sinks"]})]}):null,d.jsxs("div",{className:"topbar-actions",children:[d.jsx("button",{type:"button","data-testid":"btn-init",disabled:!!j,onClick:Ve,children:"Draft config"}),d.jsx("button",{type:"button","data-testid":"btn-index",disabled:!!j,onClick:()=>fr(!0),children:"Index"}),d.jsx("button",{type:"button","data-testid":"btn-review",className:"btn primary",disabled:!!j,onClick:Xn,children:"Review"})]})]}),d.jsxs("div",{className:"alerts",children:[I?d.jsxs("div",{className:"error","data-testid":"error",role:"alert",children:[d.jsx("span",{children:I}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>w(""),"aria-label":"Dismiss error",children:"×"})]}):null,te?d.jsxs("div",{className:"banner","data-testid":"status-note",children:[d.jsx("span",{children:te}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>Q(""),"aria-label":"Dismiss",children:"×"})]}):null,((gi=p==null?void 0:p.index)!=null&&gi.stale||g!=null&&g.stale)&&(t==="review"||t==="architecture")?d.jsx("div",{className:"banner stale","data-testid":"index-stale",children:"Index is stale — files changed since the last extract. Index again before trusting this walk."}):null,((jo=p==null?void 0:p.index)==null?void 0:jo.django_boot)==="failed"||(g==null?void 0:g.django_boot)==="failed"?d.jsx("div",{className:"banner warn","data-testid":"django-boot-failed",children:((mi=p==null?void 0:p.index)==null?void 0:mi.django_boot_detail)||(g==null?void 0:g.django_boot_detail)||"django.setup() failed"}):null,(yi=p==null?void 0:p.workspace)!=null&&yi.dirty_overlaps_review&&t==="review"?d.jsxs("div",{className:"banner warn","data-testid":"dirty-tree",children:["Uncommitted files overlap this review: ",(p.workspace.dirty_overlap||[]).slice(0,6).join(", ")]}):null,p!=null&&p.what_if?d.jsxs("div",{className:"banner whatif","data-testid":"whatif-banner",children:[d.jsxs("span",{children:["Hypothetical walk from"," ",d.jsx("strong",{children:((vi=p.node)==null?void 0:vi.name)||"this node"}),". Loadpath ignored Base/Head and asked which sinks would feel this node change — not a filter of the current map."]}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-exit-whatif",onClick:_t,children:x?"Back to git range":"Back to architecture"})]}):null,Y?d.jsx("div",{className:"banner","data-testid":"workspace-loading",children:j||"Loading workspace…"}):null]}),d.jsxs("div",{className:"stage","aria-busy":Y||re,children:[t==="review"&&d.jsxs("div",{className:"content","data-testid":"review-layout",children:[d.jsx("aside",{className:"brief","data-testid":"brief",children:p?d.jsx(ij,{review:p,findings:_s,aiNote:me,busy:!!j,tourIndex:Z,onTour:se,onAskAi:pi,onCopy:ci,onPost:Vr,onSelect:Ye,onOpenFile:Gr,onExport:pr,history:Mt,diff:ui,onReopen:Yr,onWaiver:(P,G)=>{o.trim()&&Te.addWaiver(o,P,G||void 0,"from review").then(ce=>{lr(ce),Q(`Waived ${P} in loadpath.yml`)})}}):Fr?d.jsxs("div",{className:"empty","data-testid":"review-restoring",children:[d.jsx("h2",{children:"Restoring last review"}),d.jsx("p",{children:"Loading the walk this machine stored last time Loadpath was open."})]}):d.jsxs("div",{className:"empty","data-testid":"review-empty",children:[d.jsx("h2",{children:"Trace the force of this diff"}),d.jsx("p",{children:"The graph is the architecture. The brief is where this change travels — not a hunk list."}),d.jsxs("ol",{children:[d.jsx("li",{children:"Point at a Django + React monorepo, or pick an indexed workspace."}),d.jsxs("li",{children:["Index it. Missing ",d.jsx("code",{children:"loadpath.yml"})," is drafted from ",d.jsx("code",{children:"manage.py"})," and"," ",d.jsx("code",{children:"src/features"}),"."]}),d.jsx("li",{children:"Review a git range, or open a pull request so base/head become a three-dot merge-base."})]})]})}),d.jsx("div",{className:"graph-wrap","data-testid":"review-graph",children:p?d.jsx(nc,{nodes:p.nodes,edges:p.edges,onWhatIf:Cn,focusPath:(bo=p.read_order[Z])==null?void 0:bo.path,...sn}):null})]}),t==="architecture"&&d.jsxs("div",{className:"content","data-testid":"architecture-panel",children:[d.jsx("aside",{className:"brief","data-testid":"architecture-brief",children:g!=null&&g.indexed?d.jsx(sj,{architecture:g,busy:!!j,onReindex:()=>fr(!1),onReview:Xn,onSelect:Ye,config:vo,health:Or,onSaveConfig:P=>{Te.saveConfig(o,P).then(G=>{lr(G),Q("Wrote loadpath.yml")})},onWaiver:(P,G,ce)=>{Te.addWaiver(o,P,G,ce).then(Ce=>{lr(Ce),Q(`Waived ${P}`)})}}):Y?d.jsx("p",{className:"muted","data-testid":"architecture-loading",children:"Loading the index summary…"}):d.jsx("p",{className:"muted","data-testid":"architecture-empty",children:"Index this repo to build the architecture graph. Review then walks that same graph for a git range — it does not start from a hunk list."})}),d.jsx("div",{className:"graph-wrap","data-testid":"architecture-graph",children:(re||g!=null&&g.graph_pending)&&!((g==null?void 0:g.nodes)||[]).length?d.jsxs("div",{className:"empty graph-loading","data-testid":"graph-loading",children:[d.jsx("h2",{children:"Drawing the architecture map…"}),d.jsx("p",{children:(Xr=g==null?void 0:g.counts)!=null&&Xr.nodes?`${g.counts.nodes} indexed nodes. The brief is ready while the graph loads.`:"Fetching the indexed graph."})]}):g!=null&&g.indexed?d.jsx(nc,{nodes:g.nodes,edges:g.edges,onWhatIf:Cn,...sn,isolateSource:null,onIsolate:void 0}):null})]}),t==="graph"&&d.jsxs("div",{className:"graph-wrap","data-testid":"graph-full",style:{height:"100%"},children:[d.jsxs("div",{className:"graph-modes",children:[d.jsxs("div",{className:"seg","aria-label":"Graph scope",children:[d.jsx("button",{type:"button","aria-pressed":b==="review","data-testid":"graph-mode-review",className:b==="review"?"active":"",onClick:()=>E("review"),children:"This review"}),d.jsx("button",{type:"button","aria-pressed":b==="architecture","data-testid":"graph-mode-architecture",className:b==="architecture"?"active":"",onClick:()=>E("architecture"),children:"Indexed architecture"})]}),d.jsxs("div",{className:"legend","aria-hidden":"true",children:[d.jsxs("span",{children:[d.jsx("i",{})," cheap"]}),d.jsxs("span",{children:[d.jsx("i",{className:"exp"})," expensive"]}),d.jsxs("span",{children:[d.jsx("i",{className:"crit"})," critical"]}),d.jsxs("span",{children:[d.jsx("i",{className:"dash"})," inferred"]}),d.jsxs("span",{children:[d.jsx("i",{className:"seed"})," changed"]}),d.jsxs("span",{children:[d.jsx("i",{className:"down"})," downstream"]})]}),d.jsx("button",{type:"button",className:gt?"chip-btn active":"chip-btn","data-testid":"graph-test-overlay","aria-pressed":gt,onClick:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")},children:"Tests"})]}),No.length||p||g!=null&&g.indexed?d.jsx(nc,{nodes:No,edges:gr,onWhatIf:Cn,...sn,...b==="architecture"?{isolateSource:null,onIsolate:void 0,nodeRoles:void 0,testOverlay:!1}:{}}):re||g!=null&&g.graph_pending?d.jsx("p",{className:"empty","data-testid":"graph-loading",children:"Drawing the architecture map…"}):d.jsx("p",{className:"empty","data-testid":"graph-empty",children:"Index the repo or run a review first. Click a node to inspect it."})]}),t==="prs"&&d.jsxs("div",{className:"pr-list","data-testid":"pr-list",children:[d.jsxs("div",{className:"pr-toolbar",children:[d.jsxs("label",{className:"field provider",children:[d.jsx("span",{children:"Provider"}),d.jsxs("select",{"data-testid":"pr-provider",value:z,onChange:P=>It(P.target.value,H,oe),children:[d.jsx("option",{value:"github",children:"GitHub"}),d.jsx("option",{value:"gitlab",children:"GitLab"}),d.jsx("option",{value:"bitbucket",children:"Bitbucket"})]})]}),d.jsxs("label",{className:"field",children:[d.jsx("span",{children:"Repository"}),d.jsx("input",{"data-testid":"pr-repo",placeholder:M.length?"Search your repos":"owner/repo",value:H,onChange:P=>It(z,P.target.value,oe),list:"scm-repos",spellCheck:!1}),d.jsx("datalist",{id:"scm-repos",children:M.map(P=>d.jsxs("option",{value:P.slug,children:[P.private?"private":"public",P.local_path?" · local":""]},P.slug))})]}),d.jsx("button",{type:"button","data-testid":"btn-refresh-repos",className:"btn",disabled:!!j||!_o(z),onClick:()=>{Rt(z)},children:"My repos"}),d.jsx("button",{type:"button","data-testid":"btn-list-prs",className:"btn",disabled:!!j,onClick:So,children:"List PRs"})]}),M.length>0?d.jsxs("p",{className:"muted scm-count","data-testid":"scm-repo-count",children:[M.length," ",z," repositor",M.length===1?"y":"ies",z==="github"&&C.github_user?` · @${String(C.github_user)}`:"",z==="gitlab"&&C.gitlab_user?` · @${String(C.gitlab_user)}`:"",z==="bitbucket"&&C.bitbucket_user?` · ${String(C.bitbucket_user)}`:""]}):null,W.length===0?d.jsxs("div",{className:"empty","data-testid":"pr-empty",children:[d.jsx("h2",{children:"No pull requests loaded"}),d.jsx("p",{children:"Sign in under Settings (or paste a token), load your repositories, then list open PRs. Reviewing a PR fills base and head from its SHAs."})]}):W.map(P=>{var G;return d.jsxs("article",{className:"pr","data-testid":`pr-${P.number}`,children:[d.jsxs("h3",{children:["#",P.number," ",P.title]}),d.jsxs("div",{className:"pr-meta muted",children:[d.jsx("span",{className:`chip ${P.draft?"":"open"}`,children:P.draft?"draft":P.state}),d.jsx("span",{children:P.author}),d.jsxs("span",{children:[P.source_branch," → ",P.target_branch]}),P.loadpath?d.jsxs("span",{className:`chip ${P.loadpath.level||""}`,"data-testid":`pr-loadpath-${P.number}`,children:[((G=P.loadpath.level)==null?void 0:G.toUpperCase())||"REVIEWED",P.loadpath.contract_break&&P.loadpath.contract_break!=="none"?` · ${P.loadpath.contract_break}`:""]}):d.jsx("span",{className:"muted",children:"no Loadpath walk yet"})]}),d.jsxs("div",{className:"pr-actions",children:[d.jsxs("a",{href:P.url,target:"_blank",rel:"noreferrer",children:["Open on ",P.provider]}),d.jsx("button",{type:"button",className:"btn primary","data-testid":`pr-review-${P.number}`,onClick:()=>void fi(P),children:"Review this PR"})]})]},`${P.provider}-${P.number}`)})]}),t==="settings"&&Pe&&d.jsxs("form",{className:"settings","data-testid":"settings-form",onSubmit:hi,children:[d.jsxs("div",{children:[d.jsx("h1",{children:"Settings"}),d.jsx("p",{className:"muted",children:"Tokens stay on this machine in ~/.loadpath/settings.json. AI runs only on residual uncertainty the graph could not close."})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Appearance"}),d.jsx("p",{className:"muted",children:"Local to this browser. High contrast is a first-class theme, not an afterthought."}),d.jsx("div",{className:"theme-grid","data-testid":"theme-grid",children:Qa.map(P=>d.jsxs("button",{type:"button","data-theme":P.id,className:we===P.id?"theme-swatch active":"theme-swatch","data-testid":`theme-${P.id}`,onClick:()=>xo(P.id),children:[d.jsx("div",{className:"swatch-bar","aria-hidden":"true"}),d.jsx("div",{className:"name",children:P.label}),d.jsx("div",{className:"group",children:P.group})]},P.id))})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Editor"}),d.jsx("p",{className:"muted",children:"Open files from the inspector and read-order in Cursor, VS Code, or the system handler."}),d.jsx("label",{htmlFor:"editor-pref",children:"Preferred editor"}),d.jsxs("select",{id:"editor-pref","data-testid":"editor-pref",defaultValue:Em(),onChange:P=>VN(P.target.value),children:[d.jsx("option",{value:"auto",children:"Auto (Cursor, then VS Code)"}),d.jsx("option",{value:"cursor",children:"Cursor"}),d.jsx("option",{value:"vscode",children:"VS Code"}),d.jsx("option",{value:"system",children:"System default"})]})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Source control"}),d.jsx("p",{className:"muted",children:"Sign in with OAuth to list every repository the account can access. Tokens stay in ~/.loadpath/settings.json. A classic PAT still works if you prefer not to register an OAuth app."}),d.jsxs("div",{className:"scm-login","data-testid":"scm-github",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitHub"}),d.jsx("p",{className:"muted",children:C.github_token_set?C.github_user?`Signed in as @${String(C.github_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.github_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-github-disconnect",onClick:()=>void yt("github"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-github-login",disabled:!!dt||!C.github_oauth_ready,onClick:()=>void hr(),children:dt?"Waiting for GitHub…":"Sign in with GitHub"})})]}),dt?d.jsxs("p",{className:"oauth-code","data-testid":"github-user-code",children:["Enter ",d.jsx("code",{children:dt.user_code})," at GitHub if the browser did not fill it in."]}):null,C.github_oauth_ready?null:d.jsx("p",{className:"muted",children:"Sign-in needs a GitHub OAuth App with Device Flow enabled. Set LOADPATH_GITHUB_CLIENT_ID or paste the client ID below."}),d.jsx("label",{htmlFor:"github_oauth_client_id",children:"GitHub OAuth client ID"}),d.jsx("input",{id:"github_oauth_client_id",name:"github_oauth_client_id","data-testid":"github-oauth-client-id",placeholder:"Ov23…",defaultValue:String(C.github_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"github_token",children:"GitHub token (optional PAT)"}),d.jsx("input",{id:"github_token",name:"github_token",type:"password",placeholder:"ghp_…",autoComplete:"off"}),d.jsx("label",{htmlFor:"github_host",children:"GitHub host (Enterprise)"}),d.jsx("input",{id:"github_host",name:"github_host","data-testid":"github-host",placeholder:"github.com",defaultValue:String(C.github_host||""),autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-gitlab",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitLab"}),d.jsx("p",{className:"muted",children:C.gitlab_token_set?C.gitlab_user?`Signed in as @${String(C.gitlab_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.gitlab_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-gitlab-disconnect",onClick:()=>void yt("gitlab"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-gitlab-login",disabled:Wn||!C.gitlab_oauth_ready,onClick:()=>void ko(),children:Wn?"Waiting for GitLab…":"Sign in with GitLab"})})]}),d.jsx("label",{htmlFor:"gitlab_host",children:"GitLab host"}),d.jsx("input",{id:"gitlab_host",name:"gitlab_host","data-testid":"gitlab-host",placeholder:"gitlab.com",defaultValue:String(C.gitlab_host||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_id",children:"GitLab OAuth application ID"}),d.jsx("input",{id:"gitlab_oauth_client_id",name:"gitlab_oauth_client_id","data-testid":"gitlab-oauth-client-id",defaultValue:String(C.gitlab_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_secret",children:"GitLab OAuth secret"}),d.jsx("input",{id:"gitlab_oauth_client_secret",name:"gitlab_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_token",children:"GitLab token (optional PAT)"}),d.jsx("input",{id:"gitlab_token",name:"gitlab_token",type:"password",placeholder:"glpat-…",autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-bitbucket",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"Bitbucket"}),d.jsx("p",{className:"muted",children:C.bitbucket_token_set?C.bitbucket_user?`Signed in as ${String(C.bitbucket_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.bitbucket_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-bitbucket-disconnect",onClick:()=>void yt("bitbucket"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-bitbucket-login",disabled:Vn||!C.bitbucket_oauth_ready,onClick:()=>void di(),children:Vn?"Waiting for Bitbucket…":"Sign in with Bitbucket"})})]}),C.bitbucket_oauth_ready?null:d.jsxs("p",{className:"muted",children:["Sign-in needs a Bitbucket OAuth consumer (key + secret). Callback URL:"," ",d.jsx("code",{children:"/api/oauth/bitbucket/callback"})," on this app origin."]}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_id",children:"Bitbucket OAuth key"}),d.jsx("input",{id:"bitbucket_oauth_client_id",name:"bitbucket_oauth_client_id","data-testid":"bitbucket-oauth-client-id",defaultValue:String(C.bitbucket_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_secret",children:"Bitbucket OAuth secret"}),d.jsx("input",{id:"bitbucket_oauth_client_secret",name:"bitbucket_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_token",children:"Bitbucket token (optional app password)"}),d.jsx("input",{id:"bitbucket_token",name:"bitbucket_token",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_username",children:"Bitbucket username (app passwords)"}),d.jsx("input",{id:"bitbucket_username",name:"bitbucket_username",defaultValue:String(C.bitbucket_username||"")})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Residual AI"}),d.jsx("label",{htmlFor:"ai_provider",children:"Provider"}),d.jsxs("select",{id:"ai_provider",name:"ai_provider",defaultValue:String(((an=C.ai)==null?void 0:an.provider)||"none"),children:[d.jsx("option",{value:"none",children:"none (graph only)"}),d.jsx("option",{value:"anthropic",children:"Anthropic"}),d.jsx("option",{value:"openai",children:"OpenAI"}),d.jsx("option",{value:"grok",children:"Grok / xAI"}),d.jsx("option",{value:"deepseek",children:"DeepSeek"}),d.jsx("option",{value:"cursor",children:"Cursor-compatible (OpenAI protocol)"}),d.jsx("option",{value:"ollama",children:"Ollama local"})]}),d.jsx("label",{htmlFor:"ai_api_key",children:"API key"}),d.jsx("input",{id:"ai_api_key",name:"ai_api_key",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"ai_model",children:"Model"}),d.jsx("input",{id:"ai_model",name:"ai_model","data-testid":"ai-model",placeholder:"optional override",defaultValue:String(((ln=C.ai)==null?void 0:ln.model)||"")}),d.jsx("label",{htmlFor:"ai_base_url",children:"Base URL"}),d.jsx("input",{id:"ai_base_url",name:"ai_base_url","data-testid":"ai-base-url",placeholder:"optional, OpenAI-compatible",defaultValue:String(((un=C.ai)==null?void 0:un.base_url)||"")}),d.jsx("button",{className:"btn primary",type:"submit","data-testid":"btn-save-settings",children:"Save"})]})]})]})]}),d.jsx(x0,{open:nt,actions:Kn,onClose:()=>lt(!1)}),je?d.jsx(KN,{initialPath:o,onClose:()=>Le(!1),onSelect:P=>{if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}Le(!1),Br(P)}}):null]})}function ij({review:t,findings:r,aiNote:o,busy:s,tourIndex:a,onTour:u,onAskAi:c,onCopy:h,onPost:p,onSelect:y,onOpenFile:x,onExport:v,history:g,diff:_,onReopen:S,onWaiver:N}){var E,I,w,j,A,$,F,Y,q,re,J,te,Q,C,V,W,U;const b=[...new Set(t.confidence.reasons||[])];return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:`merge-box ${t.confidence.level}`,children:[d.jsxs("div",{className:`level ${t.confidence.level}`,children:[t.confidence.level.toUpperCase()," — ",t.title]}),b.length?d.jsx("ul",{className:"reasons",children:b.map(M=>d.jsx("li",{children:M},M))}):null,t.what_if?d.jsx("span",{className:"chip whatif","data-testid":"whatif-chip",children:"what-if"}):null,t.low_risk?d.jsx("span",{className:"chip",children:"low-risk"}):null,t.change_kinds.map(M=>d.jsx("span",{className:"chip",children:ns(M)},M)),(E=t.contract_break)!=null&&E.kind&&t.contract_break.kind!=="none"?d.jsxs("span",{className:`chip ${t.contract_break.kind==="breaking"?"blocker":""}`,"data-testid":"contract-kind",children:["contract ",t.contract_break.kind]}):null]}),d.jsxs("div",{className:"metrics",children:[d.jsxs("div",{className:"metric",children:[d.jsxs("div",{className:"n",children:[t.confidence.covered_sinks,"/",t.confidence.sinks]}),d.jsx("div",{className:"l",children:"Sinks tested"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:r.length}),d.jsx("div",{className:"l",children:"Findings"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:t.residuals.length}),d.jsx("div",{className:"l",children:"Residuals"})]})]}),d.jsx("pre",{className:"headline",children:t.headline}),(t.checklist||[]).length?d.jsxs("details",{className:"section",open:!0,"data-testid":"merge-checklist",children:[d.jsxs("summary",{children:["Merge checklist"," ",d.jsx("span",{className:"count",children:(t.checklist||[]).filter(M=>M.status==="todo").length})]}),(t.checklist||[]).map(M=>d.jsxs("div",{className:`check-item ${M.status}`,children:[d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.status}`,children:M.status}),M.title]}),M.detail?d.jsx("div",{className:"why",children:M.detail}):null,M.body?d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body||"")},children:"Copy test"}):null,M.kind==="finding"&&M.status==="todo"&&M.rule?d.jsx("button",{type:"button",className:"btn",onClick:()=>N(M.rule,M.node_id),children:"Waive in loadpath.yml"}):null]},M.id))]}):null,t.index?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Index ",d.jsx("span",{className:"count",children:t.index.counts.nodes})]}),d.jsxs("div",{className:"muted",children:["Walked ",t.index.counts.nodes," nodes / ",t.index.counts.edges," edges",t.index.reindex_skipped?" from an unchanged index":t.index.reindexed?" after an incremental refresh":" from the existing index",t.index.django_boot&&t.index.django_boot!=="off"?` · Django boot ${t.index.django_boot}`:"",(I=t.workspace)!=null&&I.three_dot?" · three-dot range":""]})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Read this ",d.jsx("span",{className:"count",children:t.read_order.length})]}),t.read_order.map((M,D)=>d.jsxs("div",{className:D===a?"read-item tour-current":"read-item",children:[d.jsxs("button",{type:"button",className:"linkish file",onClick:()=>u(D),children:[D+1,". ",M.path]}),d.jsx("div",{className:"why",children:M.why}),d.jsx("button",{type:"button",className:"btn",onClick:()=>x(M.path),children:"Open"})]},M.path)),t.read_order.length>0?d.jsxs("div",{className:"btn-row tour-row",children:[d.jsx("button",{type:"button",className:"btn","data-testid":"btn-tour-prev",disabled:a<=0,onClick:()=>u(Math.max(0,a-1)),children:"Previous"}),d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-tour-next",disabled:a>=t.read_order.length-1,onClick:()=>u(Math.min(t.read_order.length-1,a+1)),children:"Next in read order"}),d.jsxs("span",{className:"muted",children:[a+1,"/",t.read_order.length]})]}):null]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Clusters ",d.jsx("span",{className:"count",children:t.clusters.length})]}),t.clusters.map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:M.title})," — ",M.files.join(", ")]},M.id))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Architecture ",d.jsx("span",{className:"count",children:r.length})]}),r.length===0?d.jsx("div",{className:"muted",children:t.architecture_note}):r.map(M=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.severity}`,children:M.severity}),M.message]})},M.rule+M.message))]}),d.jsx(Im,{cards:t.deepening}),(j=(w=t.contract_break)==null?void 0:w.reasons)!=null&&j.length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Contract ",d.jsx("span",{className:"count",children:t.contract_break.kind})]}),t.contract_break.reasons.map(M=>d.jsx("div",{className:"muted",children:M},M)),($=(A=t.contract_break.sides)==null?void 0:A.rows)!=null&&$.length?d.jsxs("table",{className:"type-table","data-testid":"contract-sides",children:[d.jsx("thead",{children:d.jsxs("tr",{children:[d.jsx("th",{children:"Field"}),d.jsx("th",{children:"Serializer"}),d.jsx("th",{children:"Zod"}),d.jsx("th",{children:"GraphQL"})]})}),d.jsx("tbody",{children:t.contract_break.sides.rows.map(M=>d.jsxs("tr",{className:M.status,children:[d.jsx("td",{children:M.field}),d.jsx("td",{children:M.serializer?"yes":"—"}),d.jsx("td",{children:M.zod?"yes":"—"}),d.jsx("td",{children:M.graphql?"yes":"—"})]},M.field))})]}):null]}):null,(F=t.auth)!=null&&F.note?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Auth"}),d.jsx("div",{className:"muted",children:t.auth.note}),(t.auth.missing_permissions||[]).map(M=>d.jsxs("div",{className:"finding",children:[d.jsx("span",{className:"chip warning",children:"missing"}),M.name]},M.id))]}):null,(t.suggested_tests||[]).length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Suggested tests ",d.jsx("span",{className:"count",children:(Y=t.suggested_tests)==null?void 0:Y.length})]}),(t.suggested_tests||[]).map(M=>d.jsxs("div",{className:"residual",children:[d.jsx("strong",{children:M.title}),d.jsx("pre",{className:"headline",children:M.body}),d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body)},children:"Copy sketch"})]},M.title))]}):null,(q=t.trend)!=null&&q.note?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Confidence trend"}),d.jsx("div",{className:"muted",children:t.trend.note}),(t.trend.points||[]).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[M.level," · ",ic(M.created_at),M.sinks!=null?` · ${M.sinks} sinks`:""]},M.id))]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Residual ",d.jsx("span",{className:"count",children:t.residuals.length})]}),d.jsx("p",{className:"muted",children:"AI is only used here, on what the graph could not close."}),t.residuals.map(M=>d.jsx("div",{className:"residual muted",children:M},M))]}),g.length?d.jsxs("details",{className:"section","data-testid":"review-history",children:[d.jsxs("summary",{children:["History ",d.jsx("span",{className:"count",children:g.length})]}),_?d.jsx("div",{className:"muted",children:_.note}):null,g.slice(0,12).map(M=>d.jsxs("button",{type:"button",className:M.id===t.id?"history-item current":"history-item",onClick:()=>S(M.id),children:[d.jsx("span",{className:`chip ${M.level||""}`,children:M.level||"walk"}),M.title||M.id.slice(0,8),d.jsx("span",{className:"muted",children:M.created_at?ic(M.created_at):""})]},M.id))]}):null,(J=(re=t.evolution)==null?void 0:re.notes)!=null&&J.length||(Q=(te=t.evolution)==null?void 0:te.hotspots)!=null&&Q.some(M=>M.commits)?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Churn & coupling"}),(((C=t.evolution)==null?void 0:C.notes)||[]).map(M=>d.jsx("div",{className:"muted",children:M},M)),(((V=t.evolution)==null?void 0:V.hotspots)||[]).filter(M=>M.commits).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("span",{className:"file",children:M.path})," — ",M.commits," commits, bus factor ",M.bus_factor]},M.path))]}):null,d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:s,onClick:c,children:"Ask configured model"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-copy-markdown",onClick:h,children:"Copy markdown"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-export-html",onClick:v,children:"Save HTML"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-post-comment",disabled:s||!!t.what_if,title:t.what_if?"Hypothetical walks are not posted to a pull request":void 0,onClick:p,children:"Post to PR"})]}),o?d.jsx("pre",{className:"headline",children:o}):null,d.jsx("div",{className:"kicker",children:"Reviewers"}),d.jsx("div",{className:"muted",children:t.suggested_reviewers.join(", ")||"—"}),(W=t.codeowners_reviewers)!=null&&W.length?d.jsxs("div",{className:"muted",children:["CODEOWNERS: ",t.codeowners_reviewers.join(", ")]}):null,(U=t.knowledge_owners)!=null&&U.length?d.jsxs("div",{className:"muted",children:["Knowledge: ",t.knowledge_owners.join(", ")]}):null]})}function sj({architecture:t,busy:r,onReindex:o,onReview:s,onSelect:a,config:u,health:c,onSaveConfig:h,onWaiver:p}){var x;const y=t.findings.filter(v=>!v.waived);return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"merge-box high",children:[d.jsxs("div",{className:"level high",children:["INDEXED — ",t.counts.nodes," nodes"]}),d.jsxs("div",{className:"muted",style:{marginTop:8},children:[t.indexed_at?`Last index ${ic(t.indexed_at)}`:"Indexed",t.incremental?" · incremental":" · full",t.stale?" · stale":"",t.django_boot&&t.django_boot!=="off"?` · Django boot ${t.django_boot}`:""]}),d.jsxs("span",{className:"chip",children:[t.counts.edges," edges"]}),t.has_config?d.jsx("span",{className:"chip",children:"loadpath.yml"}):null]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Bounded contexts"}),Object.values(t.contexts).map(v=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v.name})," — ",(v.django_apps||[]).join(", ")||"no apps"," ·"," ",(v.owners||[]).join(", ")||"unowned"]},v.name))]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Rules ",d.jsx("span",{className:"count",children:(t.rules||[]).length})]}),(t.rules||[]).map(v=>d.jsx("div",{className:"muted",children:v},v))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Findings ",d.jsx("span",{className:"count",children:y.length})]}),y.length===0?d.jsx("div",{className:"muted",children:"No architecture rule hits on the full graph."}):y.map(v=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>v.node_id&&a(v.node_id),children:[d.jsx("span",{className:`chip ${v.severity}`,children:v.severity}),v.message]})},v.rule+v.message))]}),d.jsx(Im,{cards:t.deepening}),(x=c==null?void 0:c.points)!=null&&x.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"architecture-health",children:[d.jsxs("summary",{children:["Health over time ",d.jsx("span",{className:"count",children:c.points.length})]}),d.jsx("div",{className:"sparkline","aria-hidden":"true",children:c.points.map(v=>d.jsx("i",{className:v.level||"",title:`${v.level} · ${v.findings} findings`,style:{height:`${8+Math.min(24,(v.findings||0)*4)}px`}},v.id||v.created_at))}),Object.entries(c.contexts).map(([v,g])=>{var _;return d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v})," — last ",((_=g[g.length-1])==null?void 0:_.findings)??0," findings"]},v)})]}):null,u?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"loadpath.yml"}),d.jsx(w0,{config:u,busy:r,onSave:h,onWaiver:p})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Types"}),d.jsx("table",{className:"type-table",children:d.jsx("tbody",{children:Object.entries(t.type_counts||{}).sort((v,g)=>g[1]-v[1]).slice(0,12).map(([v,g])=>d.jsxs("tr",{children:[d.jsx("td",{children:li(v)}),d.jsx("td",{children:g})]},v))})})]}),d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:r,onClick:o,"data-testid":"btn-full-reindex",children:"Full reindex"}),d.jsx("button",{type:"button",className:"btn primary",disabled:r,onClick:s,children:"Review against this index"})]})]})}function Im({cards:t}){const r=t||[];return r.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"deepening-list",children:[d.jsxs("summary",{children:["Depth ",d.jsx("span",{className:"count",children:r.length})]}),d.jsx("p",{className:"muted",children:"Deepening opportunities: more behaviour behind a smaller interface, at a real seam."}),r.map(o=>d.jsxs("div",{className:"finding","data-testid":"deepening-card",children:[d.jsx("span",{className:`chip ${o.strength}`,children:_0(o.strength)}),o.top?d.jsx("span",{className:"chip",children:"top"}):null,d.jsx("strong",{children:o.title}),d.jsx("div",{className:"why",children:o.message}),o.deletion_test?d.jsxs("div",{className:"muted",children:["Deletion test: ",o.deletion_test]}):null,o.before&&o.after?d.jsxs("div",{className:"muted",children:[o.before," → ",o.after]}):null]},o.rule+o.title))]}):null}Pm(Mm());m0.createRoot(document.getElementById("root")).render(d.jsx(L.StrictMode,{children:d.jsx(oj,{})}));export{Kk as L,uj as a,aj as c,d as j,lj as l,L as r,li as t}; + M${Y.x},${Y.y}h${Y.width}v${Y.height}h${-Y.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}_m.displayName="MiniMap";const zk=L.memo(_m),Dk=t=>r=>t?`${Math.max(1/r.transform[2],1)}`:void 0,Ok={[oi.Line]:"right",[oi.Handle]:"bottom-right"};function Fk({nodeId:t,position:r,variant:o=oi.Handle,className:s,style:a=void 0,children:u,color:c,minWidth:h=10,minHeight:p=10,maxWidth:y=Number.MAX_VALUE,maxHeight:x=Number.MAX_VALUE,keepAspectRatio:v=!1,resizeDirection:g,autoScale:_=!0,shouldResize:S,onResizeStart:N,onResize:b,onResizeEnd:E}){const I=Qg(),w=typeof t=="string"?t:I,j=Ge(),A=L.useRef(null),$=o===oi.Handle,F=De(L.useCallback(Dk($&&_),[$,_]),Qe),Y=L.useRef(null),q=r??Ok[o];L.useEffect(()=>{if(!(!A.current||!w))return Y.current||(Y.current=a_({domNode:A.current,nodeId:w,getStoreItems:()=>{const{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,domNode:W}=j.getState();return{nodeLookup:J,transform:te,snapGrid:Q,snapToGrid:C,nodeOrigin:V,paneDomNode:W}},onChange:(J,te)=>{const{triggerNodeChanges:Q,nodeLookup:C,parentLookup:V,nodeOrigin:W}=j.getState(),U=[],M={x:J.x,y:J.y},D=C.get(w);if(D&&D.expandParent&&D.parentId){const H=D.origin??W,R=J.width??D.measured.width??0,z=J.height??D.measured.height??0,ne={id:D.id,parentId:D.parentId,rect:{width:R,height:z,..._g({x:J.x??D.position.x,y:J.y??D.position.y},{width:R,height:z},D.parentId,C,H)}},oe=$c([ne],C,V,W);U.push(...oe),M.x=J.x?Math.max(H[0]*R,J.x):void 0,M.y=J.y?Math.max(H[1]*z,J.y):void 0}if(M.x!==void 0&&M.y!==void 0){const H={id:w,type:"position",position:{...M}};U.push(H)}if(J.width!==void 0&&J.height!==void 0){const R={id:w,type:"dimensions",resizing:!0,setAttributes:g?g==="horizontal"?"width":"height":!0,dimensions:{width:J.width,height:J.height}};U.push(R)}for(const H of te){const R={...H,type:"position"};U.push(R)}Q(U)},onEnd:({width:J,height:te})=>{const Q={id:w,type:"dimensions",resizing:!1,dimensions:{width:J,height:te}};j.getState().triggerNodeChanges([Q])}})),Y.current.update({controlPosition:q,boundaries:{minWidth:h,minHeight:p,maxWidth:y,maxHeight:x},keepAspectRatio:v,resizeDirection:g,onResizeStart:N,onResize:b,onResizeEnd:E,shouldResize:S}),()=>{var J;(J=Y.current)==null||J.destroy()}},[q,h,p,y,x,v,N,b,E,S]);const re=q.split("-");return d.jsx("div",{className:ot(["react-flow__resize-control","nodrag",...re,o,s]),ref:A,style:{...a,scale:F,...c&&{[$?"backgroundColor":"borderColor"]:c}},children:u})}L.memo(Fk);const Hk={"arch.context":0,"django.app":0,"django.route":1,"django.websocket_route":1,"fastapi.route":1,"django.url_name":2,"django.view":3,"django.viewset_action":3,"django.permission":3,"django.throttle":3,"django.serializer":4,"django.form":4,"graphql.type":4,"fastapi.model":4,"django.serializer_field":5,"django.service":5,"graphql.field":5,"django.model":6,"django.field":7,"django.relation":7,"django.task":8,"django.receiver":8,"django.signal":8,"django.test":8,"django.migration_op":8,"django.admin":8,"django.management_command":8,"django.consumer":8,"django.cache_key":8,"django.feature_flag":8,"django.side_effect":8,"openapi.path":9,"graphql.operation":9,"react.api_client":10,"django.htmx":10,"react.query_key":11,"react.hook":11,"react.feature":11,"react.route":12,"react.page":12,"react.server_action":12,"django.template":12,"react.component":13,"react.context":13,"react.form_schema":14,"react.test":14};function si(t){return Hk[t]??8}const zn=208,Dr=64,ai=88,Dc=28,Bk=8;function Vk(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function Sm(t,r=[]){const o=new Map;if(!t.length)return o;const s=new Map;for(const w of t){const j=si(w.type),A=s.get(j)??[];A.push(w),s.set(j,A)}const u=[...s.keys()].sort((w,j)=>w-j).map(w=>[...s.get(w)??[]].sort((j,A)=>j.name.localeCompare(A.name)||j.id.localeCompare(A.id))),c=new Set(t.map(w=>w.id)),h=new Map,p=new Map;for(const w of t)h.set(w.id,[]),p.set(w.id,[]);for(const w of r)!c.has(w.src)||!c.has(w.dst)||w.src===w.dst||(p.get(w.src).push(w.dst),h.get(w.dst).push(w.src));const y=new Map;u.forEach((w,j)=>{for(const A of w)y.set(A.id,j)});const x=new Map,v=()=>{for(const w of u)w.forEach((j,A)=>x.set(j.id,A))};v();const g=(w,j)=>{const A=w.map(($,F)=>{const Y=j($.id).map(re=>x.get(re)).filter(re=>re!==void 0),q=Vk(Y);return{n:$,bary:Number.isNaN(q)?F:q,name:$.name,id:$.id}});return A.sort(($,F)=>$.bary-F.bary||$.name.localeCompare(F.name)||$.id.localeCompare(F.id)),A.map($=>$.n)},_=w=>j=>y.get(j)===w;for(let w=0;w(h.get(A)??[]).filter(_(j-1))),v();for(let j=u.length-2;j>=0;j--)u[j]=g(u[j],A=>(p.get(A)??[]).filter(_(j+1))),v()}const S=zn+ai,N=Dr+Dc,b=Math.max(...u.map(w=>w.length),1),E=[];let I=0;for(let w=0;wY.id)),A=new Set((u[w+1]??[]).map(Y=>Y.id));let $=0;if(A.size)for(const Y of r)j.has(Y.src)&&A.has(Y.dst)&&($+=1);const F=Math.min(120,Math.max(0,($-2)*12));I+=S+F}return u.forEach((w,j)=>{const A=(b-w.length)*N/2;w.forEach(($,F)=>{o.set($.id,{x:E[j]??0,y:A+F*N})})}),o}const xc=[{id:"layers",label:"Architecture layers"},{id:"flow",label:"Edge flow"},{id:"radial",label:"Radial"},{id:"grid",label:"Compact grid"}],Wk=new Set(xc.map(t=>t.id)),km="loadpath.graphLayout",Uk=8,Gk=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","openapi.path","django.consumer","django.websocket_route","django.template","graphql.operation","fastapi.route"]),Nm=90,Yk=new Set(["django.field","django.serializer_field","django.relation","django.test","react.test","graphql.field","django.url_name","django.throttle"]),wp={"arch.context":"#edf2f4","django.app":"#8d99ae","django.route":"#4cc9f0","django.url_name":"#4cc9f0","django.view":"#4895ef","django.viewset_action":"#4361ee","django.permission":"#7b8cde","django.serializer":"#f4a261","django.form":"#e9c46a","django.serializer_field":"#e9c46a","django.service":"#90be6d","django.model":"#2a9d8f","django.field":"#8ac926","django.task":"#e76f51","django.receiver":"#e85d04","django.signal":"#f4a261","django.test":"#6c757d","django.admin":"#adb5bd","django.migration_op":"#9d4edd","django.consumer":"#e76f51","django.websocket_route":"#4cc9f0","django.template":"#c77dff","django.htmx":"#ff6b6b","django.cache_key":"#6c757d","django.feature_flag":"#f4a261","django.side_effect":"#e85d04","graphql.type":"#00bbf9","graphql.operation":"#00bbf9","fastapi.route":"#4cc9f0","fastapi.model":"#f4a261","openapi.path":"#00bbf9","react.api_client":"#ff6b6b","react.query_key":"#adb5bd","react.hook":"#7b2cbf","react.feature":"#9d4edd","react.route":"#c77dff","react.page":"#c77dff","react.server_action":"#e76f51","react.component":"#9d4edd","react.form_schema":"#ffd166","react.test":"#6c757d"},Xk=Math.PI*(3-Math.sqrt(5)),jm=220,qk=26,Kk={0:"context",1:"routes",2:"url names",3:"views",4:"serializers",5:"services",6:"models",7:"fields",8:"jobs / signals",9:"openapi",10:"api client",11:"hooks",12:"pages",13:"components",14:"forms / tests"};function bm(t){return t.startsWith("react.")?"react":t.startsWith("openapi.")||t.startsWith("graphql.")||t.startsWith("fastapi.")?"stitch":t.startsWith("arch.")?"arch":"django"}function aj(t){return wp[t]?wp[t]:t.startsWith("react.")?"#9d4edd":t.startsWith("openapi.")?"#00bbf9":"#4a5568"}function Qk(t){return t>=Nm?"3d":"2d"}function Zk(t){return t>=Nm?"overview":"full"}function Jk(t,r,o=1){const s=new Set([t]);let a=new Set([t]);for(let u=0;uo.families.has(bm(h.type)));o.detail==="overview"&&(s=s.filter(h=>!Yk.has(h.type)));const a=new Set(s.map(h=>h.id)),u=r.filter(h=>a.has(h.src)&&a.has(h.dst)),c=o.focusId?Jk(o.focusId,u,1):new Set;if(o.neighborhoodOnly&&o.focusId&&c.size){s=s.filter(p=>c.has(p.id));const h=new Set(s.map(p=>p.id));return{nodes:s,edges:u.filter(p=>h.has(p.src)&&h.has(p.dst)),neighborIds:c}}return{nodes:s,edges:u,neighborIds:c}}function tN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>`${s.name} ${s.qualified_name} ${s.type} ${s.file_path||""} ${s.context||""}`.toLowerCase().includes(o)).slice(0,24):[]}function nN(t,r,o,s){const a=new Set(t.map(N=>N.id));if(!a.has(o))return{nodeIds:new Set,edgeIds:new Set};const u=new Map,c=new Map;for(const N of r){if(!a.has(N.src)||!a.has(N.dst))continue;const b=u.get(N.src)??[];b.push({dst:N.dst,id:N.id}),u.set(N.src,b);const E=c.get(N.dst)??[];E.push({src:N.src,id:N.id}),c.set(N.dst,E)}const h=new Set(t.filter(N=>Gk.has(N.type)).map(N=>N.id)),p=h.size?h:a,y=new Set,x=[o];for(;x.length;){const N=x.pop();if(!y.has(N)){y.add(N);for(const b of u.get(N)??[])y.has(b.dst)||x.push(b.dst)}}const v=new Set([o]),g=[...p].filter(N=>y.has(N)),_=new Set(g);for(;g.length;){const N=g.pop();v.add(N);for(const b of c.get(N)??[])y.has(b.src)&&!_.has(b.src)&&(_.add(b.src),g.push(b.src))}const S=new Set;for(const N of r)v.has(N.src)&&v.has(N.dst)&&S.add(N.id);return{nodeIds:v,edgeIds:S}}function lj(t){const r=new Map;for(const s of t){const a=si(s.type),u=r.get(a)??[];u.push(s),r.set(a,u)}const o=new Map;for(const[s,a]of r){a.sort((c,h)=>c.name.localeCompare(h.name));const u=s*jm;a.forEach((c,h)=>{if(a.length===1){o.set(c.id,{x:u,y:0,z:0});return}const p=qk*Math.sqrt(h+1),y=h*Xk;o.set(c.id,{x:u,y:p*Math.cos(y),z:p*Math.sin(y)})})}return o}function uj(t){const r=new Map;for(const o of t){const s=si(o.type);r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>o[0]-s[0]).map(([o,s])=>({layer:o,x:o*jm,count:s}))}function rN(){try{if(typeof localStorage>"u")return"layers";const t=localStorage.getItem(km);return t&&Wk.has(t)?t:"layers"}catch{return"layers"}}function oN(t){try{if(typeof localStorage>"u")return;localStorage.setItem(km,t)}catch{}}function iN(t){return t==="layers"||t==="flow"}function sN(t){if(!t.length)return Number.NaN;const r=[...t].sort((s,a)=>s-a),o=Math.floor(r.length/2);return r.length%2?r[o]:(r[o-1]+r[o])/2}function ts(t,r){return t.name.localeCompare(r.name)||t.id.localeCompare(r.id)}function aN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.flat().map(S=>S.id)),a=new Map,u=new Map;for(const S of t.flat())a.set(S.id,[]),u.set(S.id,[]);for(const S of r)!s.has(S.src)||!s.has(S.dst)||S.src===S.dst||(u.get(S.src).push(S.dst),a.get(S.dst).push(S.src));const c=new Map;t.forEach((S,N)=>{for(const b of S)c.set(b.id,N)});const h=new Map,p=()=>{for(const S of t)S.forEach((N,b)=>h.set(N.id,b))};p();const y=(S,N)=>{const b=S.map((E,I)=>{const w=N(E.id).map(A=>h.get(A)).filter(A=>A!==void 0),j=sN(w);return{n:E,bary:Number.isNaN(j)?I:j,name:E.name,id:E.id}});return b.sort((E,I)=>E.bary-I.bary||E.name.localeCompare(I.name)||E.id.localeCompare(I.id)),b.map(E=>E.n)},x=S=>N=>c.get(N)===S;for(let S=0;S(a.get(b)??[]).filter(x(N-1))),p();for(let N=t.length-2;N>=0;N--)t[N]=y(t[N],b=>(u.get(b)??[]).filter(x(N+1))),p()}const v=zn+ai,g=Dr+Dc,_=Math.max(...t.map(S=>S.length),1);return t.forEach((S,N)=>{const b=(_-S.length)*g/2;S.forEach((E,I)=>{o.set(E.id,{x:N*v,y:b+I*g})})}),o}function lN(t,r){const o=new Set(t.map(h=>h.id)),s=Math.max(t.length-1,0),a=new Map;for(const h of t)a.set(h.id,0);for(let h=0;h(a.get(y.dst)||0)&&(a.set(y.dst,x),p=!0)}if(!p)break}const u=new Map;for(const h of t){const p=a.get(h.id)||0,y=u.get(p)??[];y.push(h),u.set(p,y)}const c=[...u.keys()].sort((h,p)=>h-p).map(h=>(u.get(h)??[]).sort(ts));return aN(c,r)}function uN(t,r){const o=new Map;if(!t.length)return o;const s=new Set(t.map(g=>g.id)),a=new Map,u=new Map;for(const g of t)a.set(g.id,[]),u.set(g.id,0);for(const g of r)!s.has(g.src)||!s.has(g.dst)||g.src===g.dst||(a.get(g.src).push(g.dst),a.get(g.dst).push(g.src),u.set(g.src,(u.get(g.src)||0)+1),u.set(g.dst,(u.get(g.dst)||0)+1));const c=[...t].sort((g,_)=>(u.get(_.id)||0)-(u.get(g.id)||0)||ts(g,_))[0]??t[0],h=new Map,p=[[c]];h.set(c.id,0);const y=[c];for(;y.length;){const g=y.shift(),_=h.get(g.id)||0,S=(a.get(g.id)??[]).map(N=>t.find(b=>b.id===N)).filter(N=>!!N).sort(ts);for(const N of S){if(h.has(N.id))continue;h.set(N.id,_+1);const b=p[_+1]??[];b.push(N),p[_+1]=b,y.push(N)}}const x=t.filter(g=>!h.has(g.id)).sort(ts);x.length&&p.push(x);const v=zn+32;return p.forEach((g,_)=>{if(_===0&&g.length===1){o.set(g[0].id,{x:0,y:0});return}const S=Math.max(_*(zn+ai),g.length<=1?zn:g.length*v/(2*Math.PI));g.forEach((N,b)=>{const E=-Math.PI/2+2*Math.PI*b/g.length;o.set(N.id,{x:Math.cos(E)*S,y:Math.sin(E)*S})})}),o}function cN(t){const r=new Map,o=[...t].sort((c,h)=>si(c.type)-si(h.type)||ts(c,h)),s=Math.max(1,Math.ceil(Math.sqrt(o.length))),a=zn+ai,u=Dr+Dc;return o.forEach((c,h)=>{r.set(c.id,{x:h%s*a,y:Math.floor(h/s)*u})}),r}function dN(t,r=[],o="layers"){return o==="flow"?lN(t,r):o==="radial"?uN(t,r):o==="grid"?cN(t):Sm(t,r)}const Ia=16,fN=12,hN=new Set(["django.route","react.route","react.page","react.server_action","django.task","django.migration_op","django.permission","django.throttle","django.admin","django.management_command","openapi.path","django.consumer","django.websocket_route","django.template","django.cache_key","django.feature_flag","django.side_effect","graphql.operation","fastapi.route"]),pN=new Set(["django.serializer","django.serializer_field","django.form","openapi.path","react.form_schema","django.route","graphql.type","graphql.field","graphql.operation","fastapi.model","fastapi.route"]),_p={"arch.context":"Ownership boundary from loadpath.yml — the context this code belongs to.","django.app":"Django app package that owns models, views, and jobs.","django.route":"HTTP URL that publishes a view. A sink: this is where a change becomes a public request.","django.url_name":"Named URL used by reverse() / {% url %} lookups.","django.view":"Request handler (class-based view, function view, or ViewSet).","django.viewset_action":"One ViewSet action (list, create, retrieve, update, destroy).","django.permission":"Auth gate on a view — who is allowed to hit this path.","django.throttle":"Rate-limit class attached to a view.","django.serializer":"Request/response contract: which fields go in and come out.","django.form":"Django form or django-filter FilterSet — the typed input contract.","django.serializer_field":"One field on a serializer or form — the typed slot on the contract.","django.service":"Internal service or use-case. Work that is not itself an HTTP sink.","django.model":"ORM model. Schema and relations live here.","django.field":"Model column. Type, indexes, and relations are the contract of the table.","django.relation":"Model-to-model relation (FK / M2M / O2O).","django.task":"Celery or Dramatiq job. Once enqueued, this is a sink.","django.receiver":"Signal handler that runs after a model event.","django.signal":"Django signal that receivers subscribe to.","django.test":"Backend test that mentions symbols on this path.","django.admin":"Django admin class for a model.","django.migration_op":"Schema migration operation (CreateModel, AlterField, …).","django.management_command":"manage.py command — an operational sink.","django.consumer":"Django Channels WebSocket/HTTP consumer. A sink once a client connects.","django.websocket_route":"ASGI WebSocket URL. A sink: this is where a change becomes a live connection.","django.template":"Django template. HTML (and HTMX) the server renders.","django.htmx":"HTMX call from a template to a URL — another published seam.","django.cache_key":"Cache get/set key. Invalidation is part of the load path.","django.feature_flag":"Feature flag checked on this path. The change may be dark-launched.","django.side_effect":"transaction.on_commit (or similar) side effect that runs after the request commits.","graphql.type":"GraphQL object/input type — a published contract.","graphql.field":"One field on a GraphQL type.","graphql.operation":"GraphQL query, mutation, or subscription. A published contract and a sink.","fastapi.route":"FastAPI path operation sitting next to Django in this repo.","fastapi.model":"Pydantic response/request model — the FastAPI contract.","openapi.path":"Generated OpenAPI operation. The typed HTTP contract between stacks.","react.api_client":"Frontend fetch or generated client call to an API path.","react.query_key":"React Query cache key. Invalidation and reads share this name.","react.hook":"Data hook wrapping query or mutation calls.","react.feature":"Frontend feature module (folder).","react.route":"Client-side route. A sink: this is a URL the user can open.","react.page":"Page or screen component rendered by a route.","react.server_action":"Next.js Server Action. A sink: the mutation runs on the server.","react.component":"UI component.","react.form_schema":"Zod (or similar) schema — typed form inputs on the client.","react.test":"Frontend test covering a page, hook, or component.","react.context":"React context provider."},gN={field_type:"Type",fields:"Fields",form_fields:"Form fields",permissions:"Permissions",throttles:"Throttles",authentication:"Authentication",pagination:"Pagination",filterset:"Filterset",bases:"Extends",on_delete:"on_delete",related_name:"related_name",unique:"Unique",db_index:"Indexed",relation:"Relation field",looks_idempotent_on_pk:"Idempotent on pk",broker:"Broker",route:"Route",url_name:"URL name",view:"View",include:"Includes",mounted_at:"Mounted at",full_path:"Full path",method:"Method",path:"Path",operation_id:"Operation",raw:"URL",kind:"Schema",exclude:"Excludes",queryset_in_serializer:"Queryset in serializer",get_queryset:"Custom get_queryset",get_serializer_class:"Dynamic serializer",dynamic:"Dynamic",fbv:"Function view",next_app:"Next.js App Router",next_pages:"Next.js Pages Router",next_kind:"Next file",next_layout:"Layout",server_action:"Server Action",typed_client:"Typed client",endpoint:"Endpoint",procedure:"Procedure",e2e:"E2E",visits:"Visits",nested_serializer:"Nested serializer",nested_serializers:"Nested serializers",method_field:"SerializerMethodField",method_fields:"Method fields",from_to_representation:"to_representation",to_representation_fields:"to_representation fields",to_representation:"Custom to_representation",serializer_classes:"get_serializer_class returns",get_serializer_class_resolved:"Serializer resolved",ninja_schema:"Ninja Schema",pydantic:"Pydantic",django_form:"Django form",mutation:"Mutation",has_error_boundary:"Error boundary",invalidation:"Cache invalidation",inferred:"Inferred stitch",generated:"Generated",shared:"Shared module",element:"Renders",model_name:"Model",field_name:"Field",op:"Operation",app:"App",feature:"Feature",from_view:"From view",mentions:"Mentions",nodeid:"Test id",task:"Task",to:"Related to",doc:"Summary",template:"Template",signal:"Signal",sender:"Sender",decorators:"Decorators",nplusone:"N+1 risk",lookups:"Lookups",null:"NULL",blank:"Blank",default:"Default",max_length:"max_length",max_digits:"max_digits",decimal_places:"decimal_places",primary_key:"Primary key",help_text:"Help text",choices:"Choices",auto_now:"auto_now",auto_now_add:"auto_now_add",basename:"Router basename",args:"Args",beat:"Beat",schedule_name:"Schedule",websocket:"WebSocket",htmx:"HTMX",blocks:"Blocks",db_table:"db_table"},Sp=["doc","field_type","method","path","operation_id","raw","route","mounted_at","full_path","url_name","view","element","fields","form_fields","exclude","nested_serializer","nested_serializers","method_fields","to_representation_fields","serializer_classes","typed_client","endpoint","procedure","visits","kind","bases","permissions","authentication","throttles","pagination","filterset","on_delete","related_name","to","unique","db_index","null","blank","default","max_length","max_digits","decimal_places","primary_key","auto_now","auto_now_add","help_text","choices","relation","nplusone","lookups","template","signal","sender","decorators","basename","args","beat","schedule_name","websocket","htmx","blocks","db_table","looks_idempotent_on_pk","broker","task","model_name","field_name","op","app","feature","from_view","include","fbv","ninja","django_form","mutation","has_error_boundary","invalidation","inferred","generated","shared","queryset_in_serializer","get_queryset","get_serializer_class","dynamic","mentions","nodeid"],kp=new Set(["referenced","placeholder","booted","line","call","from","import","local","source","file","plain_handler","string_ref","pagination_sink","match","via","generated_client","django","react","superseded_by_generated","foreign_app","imported"]),mN=new Set(["looks_idempotent_on_pk","null","blank"]),yN=new Set(["inferred","generated","mutation","fbv","ninja","filterset","next_app","next_pages","server_action","e2e","ninja_schema","pydantic","method_field","trpc"]);function vN(t){return _p[t]?_p[t]:t.startsWith("react.")?"A React node on the load path.":t.startsWith("django.")?"A Django node on the load path.":t.startsWith("openapi.")?"A stitch node between Django and React.":"A node on the architecture graph."}function xN(t,r,o){const s=new Map(r.map(g=>[g.id,g])),a=[];hN.has(t.type)&&a.push("sink"),pN.has(t.type)&&a.push("contract");const u=t.extra??{};u.inferred&&a.push("inferred"),u.generated&&a.push("generated"),u.mutation&&a.push("mutation"),u.fbv&&a.push("function view"),u.ninja&&a.push("ninja"),u.ninja_schema&&a.push("ninja schema"),u.next_app&&a.push("app router"),u.typed_client&&a.push(String(u.typed_client)),u.e2e&&a.push("e2e"),u.filterset===!0&&a.push("filterset");const c=o.filter(g=>g.dst===t.id),h=o.filter(g=>g.src===t.id),p=c.slice(0,Ia).map(g=>Ra(g,s,g.src)),y=h.slice(0,Ia).map(g=>Ra(g,s,g.dst)),x=t.file_path?`${t.file_path}${t.start_line?`:${t.start_line}`:""}`:void 0,v={type:t.type,typeLabel:ns(li(t.type)),layer:Kk[si(t.type)]??"other",purpose:vN(t.type),name:t.name,qualifiedName:t.qualified_name,file:x,context:t.context,roles:a,facts:_N(u).filter(g=>!(g.key==="app"&&g.value===t.context)),inputs:p,outputs:y,extraInputs:Math.max(0,c.length-Ia),extraOutputs:Math.max(0,h.length-Ia),degreeIn:c.length,degreeOut:h.length,inputKinds:Np(c.map(g=>Ra(g,s,g.src))),outputKinds:Np(h.map(g=>Ra(g,s,g.dst))),pathSummary:""};return v.pathSummary=wN(v),v}function Np(t){const r=new Map;for(const o of t){const s=o.edgeLabel||o.edgeType.replaceAll("_"," ");r.set(s,(r.get(s)||0)+1)}return[...r.entries()].sort((o,s)=>s[1]-o[1]||o[0].localeCompare(s[0])).map(([o,s])=>({label:o,count:s}))}function wN(t){const r=t.inputKinds.map(s=>`${s.label} ×${s.count}`).join(", "),o=t.outputKinds.map(s=>`${s.label} ×${s.count}`).join(", ");return r&&o?`${r} → this → ${o}`:o?`this → ${o}`:r?`${r} → this`:""}function Ra(t,r,o){const s=r.get(o),a=o.includes(":")?o.slice(o.indexOf(":")+1):o;return{id:o,name:(s==null?void 0:s.name)||a,type:(s==null?void 0:s.type)||"",typeLabel:s?ns(li(s.type)):"",edgeType:t.type,edgeLabel:ns(t.type),inferred:t.confidence<.8}}function _N(t){const r=[...Sp.filter(a=>a in t),...Object.keys(t).filter(a=>!Sp.includes(a)&&!kp.has(a))],o=[],s=new Set;for(const a of r){if(s.has(a)||kp.has(a)||yN.has(a))continue;s.add(a);const u=SN(a,t[a]);u!=null&&o.push({key:a,label:gN[a]??ns(a),value:u})}return o}function SN(t,r){if(r==null)return null;if(typeof r=="boolean")return!r&&!mN.has(t)?null:r?"yes":"no";if(typeof r=="number")return String(r);if(typeof r=="string")return r.trim()||null;if(Array.isArray(r)){if(r.some(u=>u&&typeof u=="object"))return kN(t,r);const o=r.map(u=>typeof u=="string"||typeof u=="number"?String(u):"").filter(Boolean);if(!o.length)return null;const s=o.slice(0,fN),a=o.length-s.length;return a>0?`${s.join(", ")} +${a} more`:s.join(", ")}return null}function kN(t,r){const o=r.slice(0,4).map(a=>{if(t==="nplusone"){const c=String(a.queryset||"queryset"),h=Array.isArray(a.accessed)?a.accessed.join("."):"",p=a.line?` L${a.line}`:"";return h?`${c} → ${h}${p}`:`${c}${p}`}if(t==="lookups"){const c=Array.isArray(a.fields)?a.fields.join(", "):"",h=String(a.kind||"filter");return c?`${h} ${c}`:h}return Object.entries(a).filter(([,c])=>c!=null&&(typeof c=="string"||typeof c=="number")).slice(0,3).map(([c,h])=>`${c}=${h}`).join(" ")});if(!o.some(Boolean))return null;const s=r.length-o.length;return s>0?`${o.join("; ")} +${s} more`:o.join("; ")}const jp=12,bp=.2,NN=.8,qa=20,jN=Dr;function bN(t,r,o){const s=o??Sm(t,r),a=[...new Set([...s.values()].map(p=>p.x))].sort((p,y)=>p-y),u=[];for(const p of r){const y=s.get(p.src),x=s.get(p.dst);if(!y||!x)continue;const v=y.y+Dr/2,g=x.y+Dr/2;if(Math.abs(v-g)S.y0-N.y0||S.y1-N.y1||S.id.localeCompare(N.id)),x=MN(y),v=Math.max(0,...x.values())+1,g=y[0].sourceX,_=EN(a,g);for(const S of y){const N=PN(x.get(S.id)??0,v),b=g+qa+Math.max(1,_-2*qa)*N;h.set(S.id,CN(S.sourceX,S.targetX,b))}}return h}function EN(t,r){const o=r-zn,s=t.find(a=>a>o+1);return s===void 0?ai:Math.max(ai,s-r)}function CN(t,r,o){const s=r-t-2*qa;return s<1?.5:Math.min(1,Math.max(0,(o-t-qa)/s))}function MN(t){const r=[],o=new Map;for(const s of t){let a=-1;for(let u=0;ur[u]+jN){a=u;break}a<0?(a=r.length,r.push(s.y1)):r[a]=Math.max(r[a],s.y1),o.set(s.id,a)}return o}function PN(t,r){return r<=1?.5:bp+(NN-bp)*t/(r-1)}const IN=new Set,RN=L.lazy(()=>I0(()=>import("./LayeredGraph3D-Dg13YVFZ.js"),[],import.meta.url).then(t=>({default:t.LayeredGraph3D}))),TN={cheap:"var(--edge-cheap)",expensive:"var(--edge-expensive)",critical:"var(--edge-critical)"},Ka={n:ke.Top,e:ke.Right,s:ke.Bottom,w:ke.Left};function LN(t,r){const o=r.x-t.x,s=r.y-t.y;return Math.abs(o)>=Math.abs(s)?o>=0?{source:"e",target:"w"}:{source:"w",target:"e"}:s>=0?{source:"s",target:"n"}:{source:"n",target:"s"}}function AN({data:t,selected:r}){const o=(t.roles||[]).map(s=>`role-${s}`).join(" ");return d.jsxs("div",{className:["lp-node",r?"selected":"",t.dim?"dim":"",o].filter(Boolean).join(" "),children:[["n","e","s","w"].map(s=>d.jsx(ii,{id:`tgt-${s}`,type:"target",position:Ka[s],isConnectable:!1},`tgt-${s}`)),d.jsx("div",{className:"t",children:li(t.type)}),d.jsx("div",{className:"n",title:t.name,children:Ar(t.name)}),["n","e","s","w"].map(s=>d.jsx(ii,{id:`src-${s}`,type:"source",position:Ka[s],isConnectable:!1},`src-${s}`))]})}const $N={load:AN},zN=new Set(["django","react","stitch","arch"]);function DN({id:t,sourceX:r,sourceY:o,targetX:s,targetY:a,sourcePosition:u,targetPosition:c,style:h,markerEnd:p,markerStart:y,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,data:b,interactionWidth:E}){const[I,w,j]=Ya({sourceX:r,sourceY:o,sourcePosition:u,targetX:s,targetY:a,targetPosition:c,borderRadius:8,stepPosition:(b==null?void 0:b.stepPosition)??.5});return d.jsx(ws,{id:t,path:I,labelX:w,labelY:j,label:x,labelStyle:v,labelShowBg:g,labelBgStyle:_,labelBgPadding:S,labelBgBorderRadius:N,style:h,markerEnd:p,markerStart:y,interactionWidth:E})}const ON={loadstep:DN};function FN({topologyKey:t}){const{fitView:r}=ll();return L.useEffect(()=>{let o=0;const s=requestAnimationFrame(()=>{o=requestAnimationFrame(()=>{r({padding:.2,maxZoom:1.15})})});return()=>{cancelAnimationFrame(s),cancelAnimationFrame(o)}},[r,t]),null}function HN(t,r,o=null,s={}){const a=new Map(t.map(v=>[v.id,v])),u=s.layout??"layers",c=iN(u),h=dN(t,r,u),p=bN(t,r,h),y=t.map(v=>{var S;const g=((S=s.roles)==null?void 0:S[v.id])||[],_=!!s.testOverlay&&!g.includes("tested")&&!g.includes("untested")&&!g.includes("test")&&!g.includes("seed");return{id:v.id,type:"load",position:h.get(v.id)??{x:0,y:0},data:{name:v.name,type:v.type,file:v.file_path,roles:g,dim:_},selected:o===v.id,sourcePosition:ke.Right,targetPosition:ke.Left,width:zn,height:Dr,style:{width:zn,height:Dr}}}),x=r.filter(v=>a.has(v.src)&&a.has(v.dst)).map(v=>{const g=TN[v.weight]||"var(--edge-cheap)",_=!!(o&&(v.src===o||v.dst===o)),S=h.get(v.src)??{x:0,y:0},N=h.get(v.dst)??{x:0,y:0},b=c?{source:"e",target:"w"}:LN(S,N);return{id:v.id,source:v.src,target:v.dst,sourceHandle:`src-${b.source}`,targetHandle:`tgt-${b.target}`,sourcePosition:Ka[b.source],targetPosition:Ka[b.target],type:c?"loadstep":"default",animated:v.weight==="critical",data:{stepPosition:p.get(v.id)??.5},style:{stroke:g,strokeWidth:v.weight==="critical"?2.4:1.2,strokeDasharray:v.confidence<.8?"6 4":void 0},markerEnd:{type:us.ArrowClosed,width:14,height:14,color:g},label:_?v.type.replaceAll("_"," "):void 0,labelStyle:_?{fill:"var(--ink)",fontSize:10,fontWeight:600}:void 0,labelBgStyle:_?{fill:"var(--graph-bg)",fillOpacity:.92}:void 0,labelBgPadding:_?[3,5]:void 0,labelBgBorderRadius:_?4:void 0}});return{rfNodes:y,rfEdges:x}}function BN({node:t,nodes:r,edges:o,onClose:s,onWhatIf:a,onSelect:u,onOpenFile:c,pinned:h,onPin:p,onIsolate:y}){const x=xN(t,r,o);return L.useEffect(()=>{const v=g=>{g.key==="Escape"&&s()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[s]),d.jsxs("aside",{className:"inspector","data-testid":"graph-inspector",children:[d.jsxs("div",{className:"inspector-head",children:[d.jsx("div",{className:"t",children:x.typeLabel}),d.jsx("div",{className:"inspector-roles",children:x.roles.map(v=>d.jsx("span",{className:"inspector-chip",children:v},v))}),d.jsx("button",{type:"button",className:"inspector-close","data-testid":"graph-inspector-close","aria-label":"Close inspector",onClick:s,children:"×"})]}),d.jsx("div",{className:"n",children:Ar(x.name)}),d.jsx("p",{className:"inspector-purpose","data-testid":"graph-inspector-purpose",children:x.purpose}),x.context?d.jsx("div",{className:"muted",children:Ar(x.context)}):null,x.file?d.jsxs("div",{className:"file-row",children:[d.jsx("div",{className:"file",children:Ar(x.file)}),c&&t.file_path?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-open-editor",onClick:()=>c(t.file_path,t.start_line),children:"Open in editor"}):null]}):null,d.jsx("div",{className:"muted",children:Ar(x.qualifiedName)}),d.jsxs("div",{className:"muted inspector-layer",children:["layer · ",x.layer]}),d.jsxs("div",{className:"muted inspector-degree","data-testid":"graph-inspector-degree",children:[x.degreeIn," in · ",x.degreeOut," out"]}),x.pathSummary?d.jsx("p",{className:"inspector-path","data-testid":"graph-inspector-path",children:x.pathSummary}):null,x.facts.length?d.jsx("dl",{className:"inspector-facts","data-testid":"graph-inspector-facts",children:x.facts.map(v=>d.jsxs("div",{className:"inspector-fact",children:[d.jsx("dt",{children:v.label}),d.jsx("dd",{children:Ar(v.value)})]},v.key))}):null,d.jsx(Ep,{title:"Inputs",testId:"graph-inspector-inputs",links:x.inputs,extra:x.extraInputs,empty:"Nothing in this graph points here.",onSelect:u}),d.jsx(Ep,{title:"Outputs",testId:"graph-inspector-outputs",links:x.outputs,extra:x.extraOutputs,empty:"This node does not point at anything in this graph.",onSelect:u}),a?d.jsx("p",{className:"whatif-hint","data-testid":"whatif-hint",children:y?"Walks a new path from this node with no git range. Isolate (next) only hides the rest of this map.":"Walks a new path from this node with no git range — as if this changed, regardless of Base/Head."}):null,d.jsxs("div",{className:"btn-row",children:[a?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-whatif",title:"Start a hypothetical walk from this node. Does not use Base/Head.",onClick:()=>a(t.id),children:"What if this changes"}):null,y?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-isolate",title:"Hide nodes that are not on a path from here to a sink. Does not start a new walk.",onClick:()=>y(t.id),children:"Isolate path to sinks"}):null,p?d.jsx("button",{type:"button",className:h?"btn primary":"btn","data-testid":"btn-pin-node",onClick:()=>p(h?null:t.id),children:h?"Unpin":"Pin"}):null]})]})}function Ep({title:t,testId:r,links:o,extra:s,empty:a,onSelect:u}){return d.jsxs("section",{className:"inspector-section","data-testid":r,children:[d.jsxs("h3",{children:[t,d.jsx("span",{className:"count",children:o.length+s})]}),o.length?d.jsx("ul",{children:o.map((c,h)=>d.jsx("li",{children:u?d.jsxs("button",{type:"button",className:"inspector-link",onClick:()=>u(c.id),children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]}):d.jsxs(d.Fragment,{children:[d.jsx("span",{className:"inspector-link-name",title:c.name,children:Ar(c.name)}),d.jsxs("span",{className:"inspector-link-meta",children:[c.typeLabel?`${c.typeLabel} · `:"",c.edgeLabel,c.inferred?" · inferred":""]})]})},`${c.edgeType}:${c.id}:${h}`))}):d.jsx("p",{className:"muted",children:a}),s?d.jsxs("p",{className:"muted",children:["+",s," more"]}):null]})}function nc({nodes:t,edges:r,onWhatIf:o,focusPath:s,selectedId:a,onSelect:u,nodeRoles:c,testOverlay:h=!1,isolateSource:p,onIsolate:y,repoPath:x,onOpenFile:v,pinnedId:g,onPin:_}){const[S,N]=L.useState(null),b=a!==void 0?a:S,E=ue=>{a===void 0&&N(ue),u==null||u(ue)},[I,w]=L.useState(null),[j,A]=L.useState(null),[$,F]=L.useState(()=>rN()),[Y,q]=L.useState(new Set(zN)),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState(!1),W=typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,U=I??Qk(t.length),M=j??Zk(t.length),D=re?b:null,H=L.useMemo(()=>p?nN(t,r,p):null,[t,r,p]),R=H?t.filter(ue=>H.nodeIds.has(ue.id)):t,z=H?r.filter(ue=>H.edgeIds.has(ue.id)):r,ne=L.useMemo(()=>eN(R,z,{detail:M,families:Y,focusId:D,neighborhoodOnly:!!D}),[R,z,M,Y,D]),oe=L.useMemo(()=>`${$}|${ne.nodes.map(ue=>ue.id).join("\0")}|${ne.edges.map(ue=>ue.id).join("\0")}`,[$,ne.nodes,ne.edges]),fe=b?t.find(ue=>ue.id===b)??null:null,{rfNodes:he,rfEdges:pe}=L.useMemo(()=>{const ue=HN(ne.nodes,ne.edges,b,{roles:c,testOverlay:h,layout:$});return W&&(ue.rfEdges=ue.rfEdges.map(je=>({...je,animated:!1}))),ue},[ne.nodes,ne.edges,b,W,c,h,$]);L.useEffect(()=>{if(!s)return;const ue=t.find(je=>je.file_path===s);ue&&E(ue.id)},[s,t]);const Z=L.useMemo(()=>tN(t,te),[t,te]),se=(ue,je)=>{E(je.id)},me=()=>{E(null),J(!1)},Ne=fe?d.jsx(BN,{node:fe,nodes:t,edges:r,onClose:me,onWhatIf:o,onSelect:E,onOpenFile:v,pinned:g===fe.id,onPin:_,onIsolate:y?ue=>{y(p===ue?null:ue)}:void 0}):null,we=ue=>{q(je=>{const Le=new Set(je);if(Le.has(ue)){if(Le.size===1)return je;Le.delete(ue)}else Le.add(ue);return Le})},ve=L.useMemo(()=>{const ue=new Set;for(const je of t)ue.add(bm(je.type));return ue},[t]),Pe=t.length-ne.nodes.length;return d.jsxs("div",{className:"impact-graph",style:{flex:1,minHeight:0,position:"relative",display:"flex",flexDirection:"column"},children:[d.jsxs("div",{className:"graph-toolbar","data-testid":"graph-toolbar",children:[d.jsxs("div",{className:"seg","aria-label":"Graph projection",children:[d.jsx("button",{type:"button","data-testid":"graph-view-2d",className:U==="2d"?"active":"","aria-pressed":U==="2d",onClick:()=>w("2d"),children:"2D map"}),d.jsx("button",{type:"button","data-testid":"graph-view-3d",className:U==="3d"?"active":"","aria-pressed":U==="3d",onClick:()=>w("3d"),children:"3D layers"})]}),d.jsxs("div",{className:"seg","aria-label":"Graph detail",children:[d.jsx("button",{type:"button","data-testid":"graph-detail-overview",className:M==="overview"?"active":"","aria-pressed":M==="overview",onClick:()=>A("overview"),children:"Overview"}),d.jsx("button",{type:"button","data-testid":"graph-detail-full",className:M==="full"?"active":"","aria-pressed":M==="full",onClick:()=>A("full"),children:"Full"})]}),d.jsx("div",{className:"seg","aria-label":"Graph families",children:["django","stitch","react"].filter(ue=>ve.has(ue)).map(ue=>d.jsx("button",{type:"button","data-testid":`graph-family-${ue}`,className:Y.has(ue)?"active":"","aria-pressed":Y.has(ue),onClick:()=>we(ue),children:ue},ue))}),U==="2d"?d.jsxs("label",{className:"graph-layout",children:["Layout",d.jsx("select",{id:"graph-layout","data-testid":"graph-layout",value:$,"aria-label":"2D layout algorithm",onChange:ue=>{var Le;const je=(Le=xc.find(nt=>nt.id===ue.target.value))==null?void 0:Le.id;je&&(F(je),oN(je))},children:xc.map(ue=>d.jsx("option",{value:ue.id,children:ue.label},ue.id))})]}):null,d.jsx("button",{type:"button",className:re?"chip-btn active":"chip-btn","data-testid":"graph-neighborhood",disabled:!b,onClick:()=>J(ue=>!ue),children:re?"Neighborhood":"Focus neighbors"}),p?d.jsx("button",{type:"button",className:"chip-btn active","data-testid":"graph-isolate-clear",onClick:()=>y==null?void 0:y(null),children:"Path isolate"}):null,d.jsxs("label",{className:"graph-search",children:[d.jsx("span",{className:"sr-only",children:"Search nodes"}),d.jsx("input",{"data-testid":"graph-search",placeholder:"Find a node",value:te,onChange:ue=>{Q(ue.target.value),V(!0)},onFocus:()=>V(!0),onBlur:()=>window.setTimeout(()=>V(!1),150)}),C&&te.trim()&&Z.length?d.jsx("ul",{className:"graph-search-hits","data-testid":"graph-search-hits",children:Z.map(ue=>d.jsx("li",{children:d.jsxs("button",{type:"button",onMouseDown:je=>je.preventDefault(),onClick:()=>{E(ue.id),Q(""),V(!1)},children:[ue.name,d.jsx("span",{className:"muted",children:li(ue.type)})]})},ue.id))}):null]}),d.jsxs("span",{className:"muted graph-count",children:[ne.nodes.length," nodes · ",ne.edges.length," edges",Pe?` · ${Pe} hidden`:""]})]}),d.jsx("div",{className:"graph-stage",children:t.length===0?d.jsxs("div",{className:"empty graph-walk-empty","data-testid":"graph-walk-empty",children:[d.jsx("h2",{children:"No typed nodes on this walk"}),d.jsx("p",{children:"This range did not hit models, views, routes, or React pages Loadpath extracts. Open the architecture map for the indexed graph."})]}):U==="3d"?d.jsxs("div",{className:"graph-3d","data-testid":"graph-3d",children:[d.jsx("p",{className:"graph-3d-hint",children:"Architecture layers are stacked in depth (Django → stitch → React). Drag to orbit, scroll to zoom, click a node to inspect it."}),d.jsx(L.Suspense,{fallback:d.jsx("p",{className:"muted graph-3d-hint",children:"Loading 3D layers…"}),children:d.jsx(RN,{nodes:ne.nodes,edges:ne.edges,selectedId:b,neighborIds:D?ne.neighborIds:IN,onSelect:ue=>{E(ue),ue||J(!1)}})}),Ne]}):d.jsxs(vm,{children:[d.jsxs(dk,{nodes:he,edges:pe,nodeTypes:$N,edgeTypes:ON,fitView:!1,minZoom:.25,nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,deleteKeyCode:null,onNodeClick:se,onPaneClick:me,proOptions:{hideAttribution:!1},"data-testid":"impact-graph",children:[d.jsx(FN,{topologyKey:oe}),d.jsx(mk,{}),d.jsx(zk,{pannable:!0,zoomable:!0,ariaLabel:"Impact graph overview",nodeColor:"var(--muted)",nodeStrokeColor:"transparent",nodeStrokeWidth:0,maskColor:"rgba(0, 0, 0, 0.45)",maskStrokeColor:"var(--accent)",maskStrokeWidth:1.4,bgColor:"var(--graph-bg)",style:{width:184,height:128}}),d.jsx(kk,{})]}),Ne]})})]})}function Em(){const t=localStorage.getItem("loadpath.editor")||"auto";return t==="cursor"||t==="vscode"||t==="system"?t:"auto"}function VN(t){localStorage.setItem("loadpath.editor",t)}async function WN(t,r,o,s=Em()){try{const a=await Te.openEditor(t,r,o??void 0,s);if(a.ok)return{ok:!0,message:`Opened ${r} in ${a.opened_with||"editor"}`};const u=a.urls||{},c=s==="vscode"?u.vscode:s==="cursor"?u.cursor:u.cursor||u.vscode;return c?(window.open(c,"_blank","noopener,noreferrer"),{ok:!0,message:`Opening ${r} via editor URL`}):{ok:!1,message:a.error||"Could not open editor"}}catch(a){return{ok:!1,message:a instanceof Error?a.message:String(a)}}}const Cp=[{value:"HEAD",label:"HEAD",group:"preset"},{value:"HEAD~1",label:"HEAD~1",group:"preset"}],UN=["preset","branch","tag","commit"];function GN(t){var a;if(!(t!=null&&t.git))return[...Cp];const r=((a=t.presets)!=null&&a.length?t.presets:Cp.map(u=>u.value)).map(u=>({value:u,label:u,group:"preset"})),o=new Set(r.map(u=>u.value)),s=[...r];for(const u of t.branches||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.current?`${u.name} (current)`:u.name,detail:u.subject,group:"branch"}));for(const u of t.tags||[])o.has(u.name)||(o.add(u.name),s.push({value:u.name,label:u.name,detail:u.subject,group:"tag"}));for(const u of t.commits||[])o.has(u.sha)||(o.add(u.sha),s.push({value:u.sha,label:u.short,detail:u.subject,group:"commit"}));return s}function YN(t,r){const o=r.trim().toLowerCase();return o?t.filter(s=>s.value.toLowerCase().includes(o)||s.label.toLowerCase().includes(o)||(s.detail||"").toLowerCase().includes(o)):t}function XN(t){return UN.map(r=>({group:r,items:t.filter(o=>o.group===r)})).filter(r=>r.items.length>0)}function qN(t){return t==="preset"?"Common":t==="branch"?"Branches":t==="tag"?"Tags":"Recent commits"}function Mp({value:t,onChange:r,placeholder:o,testId:s,menuTestId:a,refs:u,onNeedRefs:c}){const h=L.useId(),p=L.useRef(null),[y,x]=L.useState(!1),[v,g]=L.useState(null),[_,S]=L.useState(0),N=L.useMemo(()=>{const j=GN(u);return v===null?j:YN(j,v)},[u,v]),b=L.useMemo(()=>XN(N),[N]);L.useEffect(()=>{y&&c()},[y,c]),L.useEffect(()=>{S(0)},[v,y]);const E=()=>{x(!1),g(null)},I=j=>{r(j.value),E()},w=j=>{if(j.key==="ArrowDown"){if(j.preventDefault(),!y){x(!0);return}S(A=>Math.min(A+1,Math.max(N.length-1,0)))}else if(j.key==="ArrowUp"){if(j.preventDefault(),!y)return;S(A=>Math.max(A-1,0))}else if(j.key==="Enter"&&y){j.preventDefault();const A=N[_];A&&I(A)}else j.key==="Escape"&&y&&(j.preventDefault(),E())};return d.jsxs("div",{className:"combo",ref:p,onBlur:j=>{j.currentTarget.contains(j.relatedTarget)||E()},children:[d.jsxs("div",{className:"combo-row",children:[d.jsx("input",{"data-testid":s,value:t,placeholder:o,spellCheck:!1,role:"combobox","aria-expanded":y,"aria-controls":h,"aria-autocomplete":"list",onChange:j=>{r(j.target.value),y&&g(j.target.value)},onKeyDown:w}),d.jsx("button",{type:"button",className:"icon-btn combo-toggle","data-testid":`${s}-toggle`,"aria-label":"Show recent refs","aria-expanded":y,onMouseDown:j=>j.preventDefault(),onClick:()=>y?E():x(!0),children:d.jsx(C0,{})})]}),y?d.jsx("div",{className:"combo-menu",id:h,role:"listbox","data-testid":a,children:b.length===0?d.jsx("div",{className:"combo-empty muted",children:"No matching refs — the typed value is kept"}):b.map(j=>d.jsxs("div",{className:"combo-group",children:[d.jsx("div",{className:"combo-heading",children:qN(j.group)}),j.items.map(A=>{const $=N.indexOf(A);return d.jsxs("button",{type:"button",role:"option","aria-selected":$===_,className:$===_?"combo-option active":"combo-option","data-testid":`ref-option-${A.group}`,onMouseDown:F=>F.preventDefault(),onMouseEnter:()=>S($),onClick:()=>I(A),children:[d.jsx("span",{className:"combo-label",children:A.label}),A.detail?d.jsx("span",{className:"combo-detail",children:A.detail}):null]},`${A.group}:${A.value}`)})]},j.group))}):null]})}function KN({initialPath:t,onSelect:r,onClose:o}){const[s,a]=L.useState(null),[u,c]=L.useState(t),[h,p]=L.useState(null),[y,x]=L.useState(""),[v,g]=L.useState(!1),_=L.useRef(null),S=L.useRef(0),N=async w=>{const j=S.current+1;S.current=j,g(!0);try{const A=await Te.browse(w);if(S.current!==j)return;a(A),c(A.path),p(A.is_git?A.path:null),x("")}catch(A){if(S.current!==j)return;x(A instanceof Error?A.message:String(A))}finally{S.current===j&&g(!1)}};L.useEffect(()=>{var w,j;N(t),(w=_.current)==null||w.focus(),(j=_.current)==null||j.select()},[t]);const b=h||(s==null?void 0:s.path)||u,E=h&&h!==(s==null?void 0:s.path)?h.split(/[\\/]/).filter(Boolean).pop():s!=null&&s.is_git?"this repository":"this folder",I=w=>{w.key==="Escape"&&(w.preventDefault(),o())};return d.jsx("div",{className:"modal-backdrop","data-testid":"repo-explorer","data-overlay":"true",onClick:o,onKeyDown:I,children:d.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"explorer-title",onClick:w=>w.stopPropagation(),children:[d.jsxs("div",{className:"modal-head",children:[d.jsxs("div",{children:[d.jsx("h2",{id:"explorer-title",children:"Select repository"}),d.jsx("p",{className:"muted",children:"Browse to a git root, or paste the full path."})]}),d.jsx("button",{type:"button",className:"btn ghost","data-testid":"explorer-cancel",onClick:o,children:"Cancel"})]}),d.jsxs("form",{className:"explorer-path",onSubmit:w=>{w.preventDefault(),N(u)},children:[d.jsx("input",{ref:_,"data-testid":"explorer-path",value:u,onChange:w=>c(w.target.value),spellCheck:!1,"aria-label":"Directory path"}),d.jsx("button",{type:"button",className:"btn",disabled:!(s!=null&&s.parent),onClick:()=>(s==null?void 0:s.parent)&&void N(s.parent),children:"Up"}),d.jsx("button",{type:"button",className:"btn",onClick:()=>s&&void N(s.home),children:"Home"}),d.jsx("button",{type:"submit",className:"btn",children:"Go"})]}),y?d.jsx("div",{className:"error",role:"alert",children:y}):null,d.jsx("div",{className:"explorer-list",role:"listbox","aria-label":"Folders","aria-busy":v,children:s!=null&&s.entries.length?s.entries.map(w=>{const j=h===w.path;return d.jsxs("button",{type:"button",role:"option","aria-selected":j,className:j?"explorer-row active":"explorer-row","data-testid":"explorer-entry","data-path":w.path,onClick:()=>p(w.path),onDoubleClick:()=>void N(w.path),children:[d.jsx(Tp,{}),d.jsx("span",{className:"explorer-name",children:w.name}),w.is_git?d.jsx("span",{className:"chip git-badge",children:"git"}):null]},w.path)}):d.jsx("div",{className:"muted explorer-empty",children:v?"Loading…":"No folders here"})}),d.jsxs("div",{className:"modal-foot",children:[d.jsx("span",{className:"muted explorer-current",title:b,children:b}),d.jsxs("button",{type:"button",className:"btn primary","data-testid":"explorer-use",disabled:!b,onClick:()=>b&&r(b),children:["Use ",E]})]})]})})}const QN={scan:{start:0,end:20},extract:{start:20,end:88},boot:{start:88,end:94},stitch:{start:94,end:99},skipped:{start:100,end:100},done:{start:100,end:100}},ZN=new Set(["scan","extract","boot","stitch"]);function JN(t){const r=t.phase||"";if(!r||r==="idle")return null;const o=QN[r];if(!o)return null;if(o.start===o.end)return o.end;const s=t.total||0;if(s<=0)return o.start;const a=Math.min(1,Math.max(0,(t.done||0)/s));return Math.round(o.start+(o.end-o.start)*a)}function ej(t){return!t.phase||t.phase==="idle"?null:typeof t.percent=="number"&&Number.isFinite(t.percent)?Math.max(0,Math.min(100,Math.round(t.percent))):JN(t)}const Qa=[{id:"obsidian",label:"Obsidian",group:"dark"},{id:"nord",label:"Nord",group:"dark"},{id:"solarized-dark",label:"Solarized Dark",group:"dark"},{id:"forest",label:"Forest",group:"dark"},{id:"rose",label:"Rose Pine",group:"dark"},{id:"amber",label:"Midnight Amber",group:"dark"},{id:"volcano",label:"Volcano",group:"dark"},{id:"lavender",label:"Lavender",group:"dark"},{id:"neon-noir",label:"Neon Noir",group:"dark"},{id:"synthwave",label:"Synthwave",group:"dark"},{id:"phosphor",label:"Phosphor",group:"dark"},{id:"aurora",label:"Aurora",group:"dark"},{id:"biolume",label:"Biolume",group:"dark"},{id:"carbon",label:"Carbon",group:"dark"},{id:"paper",label:"Paper",group:"light"},{id:"solarized-light",label:"Solarized Light",group:"light"},{id:"seafoam",label:"Seafoam",group:"light"},{id:"high-contrast",label:"High Contrast",group:"light"},{id:"sakura",label:"Sakura",group:"light"},{id:"citrus",label:"Citrus",group:"light"},{id:"peach",label:"Peach Fuzz",group:"light"},{id:"candy",label:"Cotton Candy",group:"light"},{id:"sky",label:"Clear Sky",group:"light"},{id:"coral",label:"Coral Reef",group:"light"}],tj="obsidian",Cm="loadpath.theme";function nj(t){return Qa.some(r=>r.id===t)}function Mm(){try{const t=localStorage.getItem(Cm)||"";if(nj(t))return t}catch{}return tj}function rj(t){var r;return((r=Qa.find(o=>o.id===t))==null?void 0:r.group)==="light"?"light":"dark"}function Pm(t){document.documentElement.dataset.theme=t,document.documentElement.style.colorScheme=rj(t);try{localStorage.setItem(Cm,t)}catch{}}const rc=[{id:"review",label:"Review",testId:"tab-review",shortcut:"1",icon:k0},{id:"architecture",label:"Architecture",testId:"tab-architecture",shortcut:"2",icon:N0},{id:"graph",label:"Impact graph",testId:"tab-graph",shortcut:"3",icon:j0},{id:"prs",label:"Pull requests",testId:"tab-prs",shortcut:"4",icon:b0},{id:"settings",label:"Settings",testId:"tab-settings",shortcut:"5",icon:E0}];function oc(t,r,o){let s;try{s=new URL(t)}catch{return}if(s.protocol!=="https:"||s.username||s.password)return;const a=s.hostname.toLowerCase();a!==r&&!a.endsWith(`.${r}`)||s.pathname.startsWith(o)&&window.open(s.toString(),"_blank","noopener,noreferrer")}function oj(){var gi,jo,mi,yi,vi,bo,Xr,an,ln,un;const[t,r]=L.useState("review"),[o,s]=L.useState(localStorage.getItem("loadpath.repo")||""),[a,u]=L.useState(localStorage.getItem("loadpath.base")||"HEAD~1"),[c,h]=L.useState(localStorage.getItem("loadpath.head")||"HEAD"),[p,y]=L.useState(null),[x,v]=L.useState(null),[g,_]=L.useState(null),[S,N]=L.useState([]),[b,E]=L.useState("review"),[I,w]=L.useState(""),[j,A]=L.useState(""),[$,F]=L.useState(null),[Y,q]=L.useState(!1),[re,J]=L.useState(!1),[te,Q]=L.useState(""),[C,V]=L.useState({}),[W,U]=L.useState([]),[M,D]=L.useState([]),[H,R]=L.useState(localStorage.getItem("loadpath.scmRepo")||""),[z,ne]=L.useState(localStorage.getItem("loadpath.provider")||"github"),[oe,fe]=L.useState(localStorage.getItem("loadpath.prNumber")||""),[he,pe]=L.useState(localStorage.getItem("loadpath.dirty")==="1"),[Z,se]=L.useState(0),[me,Ne]=L.useState(""),[we,ve]=L.useState(Mm),[Pe,ue]=L.useState(!1),[je,Le]=L.useState(!1),[nt,lt]=L.useState(!1),[ut,Ye]=L.useState(null),[wt,Yt]=L.useState(null),[gt,mt]=L.useState(localStorage.getItem("loadpath.testOverlay")==="1"),[Ct,ct]=L.useState(null),[et,On]=L.useState(localStorage.getItem("loadpath.watch")==="1"),[Mt,kn]=L.useState([]),[ui,Fn]=L.useState(null),[vo,lr]=L.useState(null),[Or,Hn]=L.useState(null),[Fr,ur]=L.useState(()=>{try{return!!(localStorage.getItem("loadpath.lastReviewId")&&(localStorage.getItem("loadpath.repo")||"").trim())}catch{return!1}}),[cr,Ft]=L.useState(null),[dt,Bn]=L.useState(null),[Vn,Nn]=L.useState(!1),[Wn,jn]=L.useState(!1),it=L.useRef(o);it.current=o;const dr=L.useRef(he);dr.current=he;const bn=L.useRef(!1);bn.current=je;const Pt=L.useRef(""),nn=L.useRef(""),xo=P=>{ve(P),Pm(P)},Ze=L.useRef(""),He=P=>{Ze.current=P,A(P)},En=P=>{let G=0,ce=!1;F(0);const Ce=()=>{Te.indexProgress(P).then(Re=>{if(!Ze.current)return;if(Re.phase&&Re.phase!=="idle"&&Re.message&&He(Re.message),ZN.has(Re.phase))ce=!0;else if(!ce)return;const mr=ej(Re);mr!=null&&(Re.phase==="scan"&&!Re.done?G=mr:G=Math.max(G,mr),F(G))}).catch(()=>{})};Ce();const Ie=window.setInterval(Ce,250);return()=>{window.clearInterval(Ie),F(null)}};L.useEffect(()=>{Te.settings().then(V).catch(()=>{}).finally(()=>ue(!0)),Te.repos().then(P=>N(P.repos)).catch(()=>{})},[]);const Un=()=>o.trim()?!0:(w("Point at a local repository path first."),!1);L.useEffect(()=>{if(t!=="architecture"||!o.trim())return;const P=o;let G=!1;return nn.current!==P&&Yn(P),Te.config(P).then(ce=>{!G&&it.current===P&&lr(ce)}).catch(()=>{}),Te.architectureHealth(P).then(ce=>{!G&&it.current===P&&Hn(ce)}).catch(()=>{}),()=>{G=!0}},[t,o]);const rn=P=>{it.current=P,s(P),localStorage.setItem("loadpath.repo",P),P.trim()!==Pt.current&&(Pt.current="",Ft(null))},Hr=L.useCallback(P=>{const G=(P??it.current).trim();return!G||Pt.current===G?Promise.resolve():(Pt.current=G,Te.gitRefs(G).then(ce=>{it.current.trim()===G&&Ft(ce)}).catch(()=>{Pt.current===G&&(Pt.current="",Ft(null))}))},[]),on=(P,G)=>{u(P),h(G),localStorage.setItem("loadpath.base",P),localStorage.setItem("loadpath.head",G)},It=(P,G,ce)=>{ne(P),R(G),localStorage.setItem("loadpath.provider",P),localStorage.setItem("loadpath.scmRepo",G),ce!==void 0&&(fe(ce),localStorage.setItem("loadpath.prNumber",ce))},Xt=P=>{y(P),se(0),Ye(wt&&P.nodes.some(G=>G.id===wt)?wt:null),ct(null),Fn(null),P.what_if||(v(P),P.id&&localStorage.setItem("loadpath.lastReviewId",P.id))},Gn=async P=>{try{const G=await Te.reviews(P);kn(G.reviews)}catch{kn([])}},wo=async P=>{try{Hn(await Te.architectureHealth(P))}catch{Hn(null)}},_o=P=>P==="github"?!!C.github_token_set:P==="gitlab"?!!C.gitlab_token_set:!!C.bitbucket_token_set,Rt=L.useCallback(async(P=z)=>{var G;try{const ce=await Te.scmRepos(P);D(ce.repos),(G=ce.user)!=null&&G.login&&V(Ce=>({...Ce,...P==="github"?{github_user:ce.user.login}:P==="gitlab"?{gitlab_user:ce.user.login}:{bitbucket_user:ce.user.login}}))}catch{D([])}},[z]);L.useEffect(()=>{if(t!=="prs")return;let P=!1;return Rt(z).catch(()=>{P||D([])}),()=>{P=!0}},[t,z,Rt]),L.useEffect(()=>{if(!dt)return;let P=!1,G=0;const ce=async()=>{try{const Ce=await Te.githubOAuthPoll(dt.flow_id);if(P)return;if(Ce.status==="complete"){Bn(null);const Ie=await Te.settings();V(Ie),Q(Ce.user?`Signed in to GitHub as ${Ce.user}`:"Signed in to GitHub"),Rt("github");return}if(Ce.status==="pending"||Ce.status==="slow_down"){G=window.setTimeout(ce,Math.max(Ce.interval||dt.interval,5)*1e3);return}Bn(null),w(Ce.status==="denied"?"GitHub sign-in was denied.":"GitHub sign-in expired. Try again.")}catch(Ce){if(P)return;Bn(null),w(Ce instanceof Error?Ce.message:String(Ce))}};return G=window.setTimeout(ce,Math.max(dt.interval,5)*1e3),()=>{P=!0,window.clearTimeout(G)}},[dt,Rt]),L.useEffect(()=>{if(!Vn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.bitbucket.connected){Nn(!1);const Re=await Te.settings();V(Re),Q(Ie.bitbucket.user?`Signed in to Bitbucket as ${Ie.bitbucket.user}`:"Signed in to Bitbucket"),Rt("bitbucket");return}if(Date.now()-ce>18e4){Nn(!1),w("Bitbucket sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;Nn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Vn,Rt]),L.useEffect(()=>{if(!Wn)return;let P=!1,G=0;const ce=Date.now(),Ce=async()=>{try{const Ie=await Te.oauthStatus();if(P)return;if(Ie.gitlab.connected){jn(!1);const Re=await Te.settings();V(Re),Q(Ie.gitlab.user?`Signed in to GitLab as ${Ie.gitlab.user}`:"Signed in to GitLab"),Rt("gitlab");return}if(Date.now()-ce>18e4){jn(!1),w("GitLab sign-in timed out. Finish in the browser, or try again.");return}G=window.setTimeout(Ce,1500)}catch(Ie){if(P)return;jn(!1),w(Ie instanceof Error?Ie.message:String(Ie))}};return G=window.setTimeout(Ce,1500),()=>{P=!0,window.clearTimeout(G)}},[Wn,Rt]);const Yn=async(P=o,G=!1)=>{if(!P.trim())return null;nn.current=P,J(!0);try{const ce=await Te.architecture(P,!1);it.current===P&&_(ce);const Ce=Te.architectureGraph(P).then(Ie=>{it.current===P&&_(Re=>Re&&{...Re,nodes:Ie.nodes,edges:Ie.edges,graph_pending:!1})});return Ce.catch(()=>{_(Ie=>Ie&&it.current===P?{...Ie,graph_pending:!1}:Ie)}).finally(()=>{nn.current===P&&J(!1)}),G&&await Ce,ce}catch(ce){throw it.current===P&&J(!1),ce}},Br=async P=>{const G=P.trim();if(!(!G||G===it.current)){if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}w(""),Q(""),y(null),v(null),_(null),E("architecture"),rn(G),q(!0),He(`Loading ${S0(G)}…`);try{await Promise.all([Yn(G),Hr(G)])}catch(ce){it.current===G&&w(ce instanceof Error?ce.message:String(ce))}finally{it.current===G&&(He(""),q(!1))}}},Xn=async()=>{if(Ze.current||!Un())return;w(""),Q(""),He("Tracing load path…"),rn(o),on(a,c);const P=En(o);try{const G=await Te.review(o,a,c,!0,dr.current);Xt(G),E("review"),r("review"),await Te.repos().then(ce=>N(ce.repos)).catch(()=>{}),await Promise.all([Yn(o),Gn(o),wo(o)])}catch(G){w(G instanceof Error?G.message:String(G))}finally{P(),He("")}},fr=async(P=!0)=>{if(Ze.current||!Un())return;w(""),Q(""),He(P?"Indexing…":"Full reindex…"),rn(o);const G=En(o);try{await Te.index(o,P);const ce=await Yn(o);await Te.repos().then(Ce=>N(Ce.repos)).catch(()=>{}),ce!=null&&ce.indexed&&(E("architecture"),r("architecture"))}catch(ce){w(ce instanceof Error?ce.message:String(ce))}finally{G(),He("")}},Ve=async()=>{if(!Ze.current&&Un()){w(""),Q(""),He("Detecting layout…"),rn(o);try{const P=await Te.init(o);Q(P.message),await Te.repos().then(G=>N(G.repos)).catch(()=>{})}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},ci=async()=>{if(p!=null&&p.markdown)try{await navigator.clipboard.writeText(p.markdown),Q("Copied markdown brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Vr=async()=>{if(!Ze.current){if(p!=null&&p.what_if){w("What-if walks are hypothetical — they are not posted to a pull request. Restore the git-range walk first.");return}if(!(p!=null&&p.markdown)||!H||!oe){w("Pick a pull request first (Pull requests tab), then post the brief.");return}He("Posting Loadpath brief…");try{const P=await Te.postComment(z,H,Number(oe),p.markdown);Q(P.updated?"Updated the Loadpath PR comment":"Posted the Loadpath PR comment")}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},So=async()=>{if(!Ze.current){w(""),He("Fetching pull requests…");try{const P=await Te.prs(z,H,"open",o.trim()||void 0);U(P.pull_requests);const G=M.find(ce=>ce.slug.toLowerCase()===H.trim().toLowerCase());G!=null&&G.local_path&&rn(G.local_path)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},hr=async()=>{w("");try{const P=await Te.githubOAuthStart();Bn(P),oc(P.verification_uri_complete,"github.com","/login/device")}catch(P){w(P instanceof Error?P.message:String(P))}},di=async()=>{w("");try{const P=await Te.bitbucketOAuthStart();Nn(!0),oc(P.authorize_url,"bitbucket.org","/site/oauth2/authorize")}catch(P){Nn(!1),w(P instanceof Error?P.message:String(P))}},ko=async()=>{w("");try{const P=await Te.gitlabOAuthStart();jn(!0),oc(P.authorize_url,new URL(P.authorize_url).hostname,"/oauth/authorize")}catch(P){jn(!1),w(P instanceof Error?P.message:String(P))}},Cn=async P=>{if(!(Ze.current||!o.trim())){w(""),He("Walking what-if path…");try{const G=await Te.whatIf(o,P);Q(`${G.title} — ${G.confidence.level} · ${(G.sinks||[]).length} sinks`),Xt({...G,markdown:G.markdown||"",index:G.index||(p==null?void 0:p.index),workspace:G.workspace||(p==null?void 0:p.workspace)}),E("review"),r("review")}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},_t=()=>{if(x){Xt(x),E("review"),r("review"),Q("Restored the last git-range walk");return}y(null),se(0),Ye(null),ct(null),Fn(null),E("architecture"),r("architecture"),Q("")},fi=async P=>{var Ie;if(Ze.current)return;It(P.provider,P.repo,String(P.number));const G=M.find(Re=>Re.slug.toLowerCase()===P.repo.toLowerCase());G!=null&&G.local_path&&rn(G.local_path),w(""),He(`Fetching ${P.provider} #${P.number}…`);const ce=(G==null?void 0:G.local_path)||o,Ce=ce?En(ce):()=>{};try{const Re=await Te.reviewPr(P.provider,P.repo,P.number,(G==null?void 0:G.local_path)||o||void 0);Xt(Re),Re.pull_request&&typeof Re.pull_request.repo_path=="string"&&rn(Re.pull_request.repo_path),on(String(Re.base||P.target_branch),String(Re.head||P.source_branch)),E("review"),r("review"),typeof((Ie=Re.pull_request)==null?void 0:Ie.repo_path)=="string"&&Gn(Re.pull_request.repo_path)}catch(Re){on(P.base_sha||P.target_branch,P.head_sha||P.source_branch),r("review"),w(Re instanceof Error?Re.message:String(Re))}finally{Ce(),He("")}},yt=async P=>{w("");try{V(await Te.oauthDisconnect(P)),z===P&&D([]),Q(`Disconnected ${P}`)}catch(G){w(G instanceof Error?G.message:String(G))}},hi=async P=>{P.preventDefault();const G=new FormData(P.currentTarget),ce={github_token:String(G.get("github_token")||""),github_oauth_client_id:String(G.get("github_oauth_client_id")||""),github_host:String(G.get("github_host")||""),gitlab_token:String(G.get("gitlab_token")||""),gitlab_host:String(G.get("gitlab_host")||""),gitlab_oauth_client_id:String(G.get("gitlab_oauth_client_id")||""),gitlab_oauth_client_secret:String(G.get("gitlab_oauth_client_secret")||""),bitbucket_token:String(G.get("bitbucket_token")||""),bitbucket_username:String(G.get("bitbucket_username")||""),bitbucket_oauth_client_id:String(G.get("bitbucket_oauth_client_id")||""),bitbucket_oauth_client_secret:String(G.get("bitbucket_oauth_client_secret")||""),ai_provider:String(G.get("ai_provider")||"none"),ai_api_key:String(G.get("ai_api_key")||""),ai_model:String(G.get("ai_model")||""),ai_base_url:String(G.get("ai_base_url")||"")},Ce=S.length?{...ce,workspaces:S.map(Ie=>({path:Ie.path,name:Ie.name}))}:ce;try{V(await Te.saveSettings(Ce)),Q("Settings saved on this machine")}catch(Ie){w(Ie instanceof Error?Ie.message:String(Ie))}},pi=async()=>{if(!(!p||Ze.current)){He("Residual analysis…");try{const P=await Te.residual(p);Ne(P.note)}catch(P){w(P instanceof Error?P.message:String(P))}finally{He("")}}},Wr=L.useRef(Xn);Wr.current=Xn;const Mn=L.useRef(t);Mn.current=t;const qn=L.useRef(!1);qn.current=nt;const Pn=L.useRef(p);Pn.current=p;const qt=L.useRef(Z);qt.current=Z,L.useEffect(()=>{const P=localStorage.getItem("loadpath.lastReviewId"),G=(localStorage.getItem("loadpath.repo")||"").trim();if(!P||!G){ur(!1);return}let ce=!1;return Te.getReview(G,P).then(Ce=>{ce||(Xt(Ce),on(Ce.base||localStorage.getItem("loadpath.base")||"HEAD~1",Ce.head||localStorage.getItem("loadpath.head")||"HEAD"),Gn(G),wo(G))}).catch(()=>{}).finally(()=>{ce||ur(!1)}),()=>{ce=!0}},[]);const Ur=L.useRef("");L.useEffect(()=>{if(!et||!o.trim())return;let P=!1;const G=async()=>{try{const Ce=await Te.workspaceStatus(o);if(P)return;Ur.current&&Ce.fingerprint!==Ur.current&&!Ze.current&&(pe(!0),dr.current=!0,localStorage.setItem("loadpath.dirty","1"),Wr.current()),Ur.current=Ce.fingerprint}catch{}};G();const ce=window.setInterval(G,2e3);return()=>{P=!0,window.clearInterval(ce)}},[et,o]),L.useEffect(()=>{const P=G=>{var Ie;if((G.metaKey||G.ctrlKey)&&G.key.toLowerCase()==="k"){G.preventDefault(),lt(Re=>!Re);return}if(qn.current){G.key==="Escape"&&(G.preventDefault(),lt(!1));return}if(bn.current){G.key==="Escape"&&(G.preventDefault(),Le(!1));return}const ce=G.target;if(ce&&(ce.tagName==="INPUT"||ce.tagName==="TEXTAREA"||ce.tagName==="SELECT"||ce.isContentEditable)){G.key==="Escape"&&ce.blur();return}if(G.key==="Escape"){w(""),Q(""),Ye(wt),ct(null);return}if(G.key==="j"||G.key==="k"){const Re=((Ie=Pn.current)==null?void 0:Ie.read_order)||[];if(!Re.length)return;G.preventDefault();const xi=qt.current,mr=G.key==="j"?Math.min(Re.length-1,xi+1):Math.max(0,xi-1);se(mr);return}const Ce=rc.find(Re=>Re.shortcut===G.key);if(Ce&&!G.metaKey&&!G.ctrlKey&&!G.altKey&&r(Ce.id),(G.metaKey||G.ctrlKey)&&G.key==="Enter"){if(Mn.current==="settings"||Mn.current==="prs"||Ze.current)return;G.preventDefault(),Wr.current()}};return window.addEventListener("keydown",P),()=>window.removeEventListener("keydown",P)},[wt]);const Gr=async(P,G)=>{if(!o.trim())return;const ce=await WN(o,P,G);ce.ok?Q(ce.message):w(ce.message)},pr=async()=>{if(p)try{const P=await Te.exportHtml(p),G=URL.createObjectURL(P),ce=document.createElement("a");ce.href=G,ce.download=`loadpath-${(p.id||"review").slice(0,8)}.html`,ce.click(),URL.revokeObjectURL(G),Q("Saved HTML brief")}catch(P){w(P instanceof Error?P.message:String(P))}},Yr=async P=>{if(o.trim()){He("Loading stored review…");try{const G=await Te.getReview(o,P);Xt(G),on(G.base||a,G.head||c),E("review"),r("review");const ce=Mt.findIndex(Ie=>Ie.id===P),Ce=ce>=0?Mt[ce+1]:void 0;if(Ce)try{Fn(await Te.reviewDiff(o,P,Ce.id))}catch{Fn(null)}}catch(G){w(G instanceof Error?G.message:String(G))}finally{He("")}}},sn={selectedId:ut,onSelect:Ye,nodeRoles:p==null?void 0:p.node_roles,testOverlay:gt,isolateSource:Ct,onIsolate:ct,repoPath:o,onOpenFile:Gr,pinnedId:wt,onPin:Yt},Kn=[{id:"review",group:"Run",label:"Review this range",hint:"⌘/Ctrl+Enter",run:()=>void Xn()},...p!=null&&p.what_if?[{id:"exit-whatif",group:"Review",label:x?"Back to git-range walk":"Exit what-if walk",run:_t}]:[],{id:"index",group:"Run",label:"Index repository",run:()=>void fr(!0)},{id:"watch",group:"Run",label:et?"Stop watching working tree":"Watch working tree",run:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")}},{id:"tests",group:"Graph",label:gt?"Hide test overlay":"Show test overlay",run:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")}},{id:"export",group:"Review",label:"Export HTML brief",run:()=>void pr()},...rc.map(P=>({id:`tab-${P.id}`,group:"Tabs",label:`Go to ${P.label}`,hint:P.shortcut,run:()=>r(P.id)})),...((p==null?void 0:p.nodes)||[]).slice(0,30).map(P=>({id:`node-${P.id}`,group:"Nodes",label:P.name,hint:li(P.type),run:()=>{Ye(P.id),r("graph")}})),...Mt.slice(0,12).map(P=>({id:`hist-${P.id}`,group:"History",label:P.title||P.id,hint:`${P.level||""} ${P.created_at||""}`.trim(),run:()=>void Yr(P.id)}))],No=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.nodes)??[]:(p==null?void 0:p.nodes)??[],[b,g,p]),gr=L.useMemo(()=>b==="architecture"?(g==null?void 0:g.edges)??[]:(p==null?void 0:p.edges)??[],[b,g,p]),Fe=p!=null&&p.index?`${p.index.counts.nodes} nodes · ${p.index.counts.edges} edges`:g!=null&&g.indexed?`${g.counts.nodes} nodes · ${g.counts.edges} edges`:"Not indexed",_s=((p==null?void 0:p.findings)||[]).filter(P=>!P.waived);return d.jsxs("div",{className:"app",children:[d.jsx("a",{className:"skip",href:"#main",children:"Skip to content"}),d.jsxs("nav",{className:"rail","data-testid":"rail","aria-label":"Primary",children:[d.jsxs("div",{className:"brand",children:[d.jsx("div",{className:"brand-mark",children:"Loadpath"}),d.jsx("div",{className:"brand-sub",children:"Load-path review"})]}),rc.map(P=>{const G=P.icon,ce=t===P.id;return d.jsxs("button",{type:"button","data-testid":P.testId,className:ce?"nav-item active":"nav-item","aria-current":ce?"page":void 0,"aria-label":P.label,onClick:()=>r(P.id),children:[d.jsx(G,{}),d.jsx("span",{children:P.label})]},P.id)}),d.jsxs("div",{className:"theme-pick",children:[d.jsx("label",{htmlFor:"theme-select",children:"Theme"}),d.jsx("select",{id:"theme-select","data-testid":"theme-select",value:we,onChange:P=>xo(P.target.value),children:["dark","light"].map(P=>d.jsx("optgroup",{label:P==="dark"?"Dark":"Light",children:Qa.filter(G=>G.group===P).map(G=>d.jsx("option",{value:G.id,children:G.label},G.id))},P))})]}),d.jsxs("div",{className:"rail-foot",children:[d.jsx("div",{className:"muted",role:"status",children:j||Fe}),d.jsxs("div",{className:"kbd-hint",children:[d.jsx("kbd",{children:"1"}),"–",d.jsx("kbd",{children:"5"})," tabs · ",d.jsx("kbd",{children:"⌘"}),d.jsx("kbd",{children:"K"})," palette · ",d.jsx("kbd",{children:"j"}),"/",d.jsx("kbd",{children:"k"})," read order"]})]})]}),d.jsxs("div",{className:"main",id:"main",children:[j?d.jsxs("div",{className:$!=null?"progress determinate":"progress",role:$!=null?"progressbar":"status","aria-label":j,"aria-live":"polite","aria-busy":"true","aria-valuemin":$!=null?0:void 0,"aria-valuemax":$!=null?100:void 0,"aria-valuenow":$??void 0,"data-testid":"progress",children:[d.jsx("i",{style:$!=null?{width:`${$}%`}:void 0}),d.jsx("span",{className:"sr-only",children:j})]}):null,d.jsxs("header",{className:"topbar","data-testid":"topbar",children:[S.length>0?d.jsxs("label",{className:"field workspace",children:[d.jsx("span",{children:"Workspace"}),d.jsxs("select",{"data-testid":"workspace-select",value:S.some(P=>P.path===o)?o:"",disabled:!!j,"aria-busy":Y,onChange:P=>{P.target.value&&Br(P.target.value)},children:[d.jsx("option",{value:"",children:"Indexed repos…"}),S.map(P=>d.jsxs("option",{value:P.path,children:[P.name,P.indexed?` (${P.counts.nodes})`:""]},P.path))]})]}):null,d.jsxs("label",{className:"field path",children:[d.jsx("span",{children:"Repository"}),d.jsxs("div",{className:"path-row",children:[d.jsx("input",{"data-testid":"repo-path",placeholder:"Local monorepo path",value:o,onChange:P=>{const G=P.target.value;s(G),G.trim()!==Pt.current&&(Pt.current="",Ft(null))},spellCheck:!1}),d.jsx("button",{type:"button",className:"icon-btn","data-testid":"btn-browse-repo","aria-label":"Browse for a local repository",onClick:()=>Le(!0),children:d.jsx(Tp,{})})]})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Base"}),d.jsx(Mp,{testId:"base-ref",menuTestId:"base-ref-menu",value:a,onChange:P=>on(P,c),placeholder:"base",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field ref",children:[d.jsx("span",{children:"Head"}),d.jsx(Mp,{testId:"head-ref",menuTestId:"head-ref-menu",value:c,onChange:P=>on(a,P),placeholder:"head",refs:cr,onNeedRefs:Hr})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Working tree"}),d.jsx("button",{type:"button",className:he?"chip-btn active":"chip-btn","data-testid":"btn-dirty","aria-pressed":he,onClick:()=>{const P=!he;pe(P),localStorage.setItem("loadpath.dirty",P?"1":"0")},children:he?"Include uncommitted":"Committed range"})]}),d.jsxs("label",{className:"field dirty",children:[d.jsx("span",{children:"Watch"}),d.jsx("button",{type:"button",className:et?"chip-btn active":"chip-btn","data-testid":"btn-watch","aria-pressed":et,onClick:()=>{const P=!et;On(P),localStorage.setItem("loadpath.watch",P?"1":"0")},children:et?"Watching":"Paused"})]}),p?d.jsxs("div",{className:`merge-box compact ${p.confidence.level}`,"data-testid":"merge-box",children:[d.jsx("div",{className:`level ${p.confidence.level}`,children:p.confidence.level.toUpperCase()}),d.jsxs("div",{className:"muted",children:[p.what_if?"what-if · ":"",p.confidence.covered_sinks,"/",p.confidence.sinks," sinks"]})]}):null,d.jsxs("div",{className:"topbar-actions",children:[d.jsx("button",{type:"button","data-testid":"btn-init",disabled:!!j,onClick:Ve,children:"Draft config"}),d.jsx("button",{type:"button","data-testid":"btn-index",disabled:!!j,onClick:()=>fr(!0),children:"Index"}),d.jsx("button",{type:"button","data-testid":"btn-review",className:"btn primary",disabled:!!j,onClick:Xn,children:"Review"})]})]}),d.jsxs("div",{className:"alerts",children:[I?d.jsxs("div",{className:"error","data-testid":"error",role:"alert",children:[d.jsx("span",{children:I}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>w(""),"aria-label":"Dismiss error",children:"×"})]}):null,te?d.jsxs("div",{className:"banner","data-testid":"status-note",children:[d.jsx("span",{children:te}),d.jsx("button",{type:"button",className:"dismiss",onClick:()=>Q(""),"aria-label":"Dismiss",children:"×"})]}):null,((gi=p==null?void 0:p.index)!=null&&gi.stale||g!=null&&g.stale)&&(t==="review"||t==="architecture")?d.jsx("div",{className:"banner stale","data-testid":"index-stale",children:"Index is stale — files changed since the last extract. Index again before trusting this walk."}):null,((jo=p==null?void 0:p.index)==null?void 0:jo.django_boot)==="failed"||(g==null?void 0:g.django_boot)==="failed"?d.jsx("div",{className:"banner warn","data-testid":"django-boot-failed",children:((mi=p==null?void 0:p.index)==null?void 0:mi.django_boot_detail)||(g==null?void 0:g.django_boot_detail)||"django.setup() failed"}):null,(yi=p==null?void 0:p.workspace)!=null&&yi.dirty_overlaps_review&&t==="review"?d.jsxs("div",{className:"banner warn","data-testid":"dirty-tree",children:["Uncommitted files overlap this review: ",(p.workspace.dirty_overlap||[]).slice(0,6).join(", ")]}):null,p!=null&&p.what_if?d.jsxs("div",{className:"banner whatif","data-testid":"whatif-banner",children:[d.jsxs("span",{children:["Hypothetical walk from"," ",d.jsx("strong",{children:((vi=p.node)==null?void 0:vi.name)||"this node"}),". Loadpath ignored Base/Head and asked which sinks would feel this node change — not a filter of the current map."]}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-exit-whatif",onClick:_t,children:x?"Back to git range":"Back to architecture"})]}):null,Y?d.jsx("div",{className:"banner","data-testid":"workspace-loading",children:j||"Loading workspace…"}):null]}),d.jsxs("div",{className:"stage","aria-busy":Y||re,children:[t==="review"&&d.jsxs("div",{className:"content","data-testid":"review-layout",children:[d.jsx("aside",{className:"brief","data-testid":"brief",children:p?d.jsx(ij,{review:p,findings:_s,aiNote:me,busy:!!j,tourIndex:Z,onTour:se,onAskAi:pi,onCopy:ci,onPost:Vr,onSelect:Ye,onOpenFile:Gr,onExport:pr,history:Mt,diff:ui,onReopen:Yr,onWaiver:(P,G)=>{o.trim()&&Te.addWaiver(o,P,G||void 0,"from review").then(ce=>{lr(ce),Q(`Waived ${P} in loadpath.yml`)})}}):Fr?d.jsxs("div",{className:"empty","data-testid":"review-restoring",children:[d.jsx("h2",{children:"Restoring last review"}),d.jsx("p",{children:"Loading the walk this machine stored last time Loadpath was open."})]}):d.jsxs("div",{className:"empty","data-testid":"review-empty",children:[d.jsx("h2",{children:"Trace the force of this diff"}),d.jsx("p",{children:"The graph is the architecture. The brief is where this change travels — not a hunk list."}),d.jsxs("ol",{children:[d.jsx("li",{children:"Point at a Django + React monorepo, or pick an indexed workspace."}),d.jsxs("li",{children:["Index it. Missing ",d.jsx("code",{children:"loadpath.yml"})," is drafted from ",d.jsx("code",{children:"manage.py"})," and"," ",d.jsx("code",{children:"src/features"}),"."]}),d.jsx("li",{children:"Review a git range, or open a pull request so base/head become a three-dot merge-base."})]})]})}),d.jsx("div",{className:"graph-wrap","data-testid":"review-graph",children:p?d.jsx(nc,{nodes:p.nodes,edges:p.edges,onWhatIf:Cn,focusPath:(bo=p.read_order[Z])==null?void 0:bo.path,...sn}):null})]}),t==="architecture"&&d.jsxs("div",{className:"content","data-testid":"architecture-panel",children:[d.jsx("aside",{className:"brief","data-testid":"architecture-brief",children:g!=null&&g.indexed?d.jsx(sj,{architecture:g,busy:!!j,onReindex:()=>fr(!1),onReview:Xn,onSelect:Ye,config:vo,health:Or,onSaveConfig:P=>{Te.saveConfig(o,P).then(G=>{lr(G),Q("Wrote loadpath.yml")})},onWaiver:(P,G,ce)=>{Te.addWaiver(o,P,G,ce).then(Ce=>{lr(Ce),Q(`Waived ${P}`)})}}):Y?d.jsx("p",{className:"muted","data-testid":"architecture-loading",children:"Loading the index summary…"}):d.jsx("p",{className:"muted","data-testid":"architecture-empty",children:"Index this repo to build the architecture graph. Review then walks that same graph for a git range — it does not start from a hunk list."})}),d.jsx("div",{className:"graph-wrap","data-testid":"architecture-graph",children:(re||g!=null&&g.graph_pending)&&!((g==null?void 0:g.nodes)||[]).length?d.jsxs("div",{className:"empty graph-loading","data-testid":"graph-loading",children:[d.jsx("h2",{children:"Drawing the architecture map…"}),d.jsx("p",{children:(Xr=g==null?void 0:g.counts)!=null&&Xr.nodes?`${g.counts.nodes} indexed nodes. The brief is ready while the graph loads.`:"Fetching the indexed graph."})]}):g!=null&&g.indexed?d.jsx(nc,{nodes:g.nodes,edges:g.edges,onWhatIf:Cn,...sn,isolateSource:null,onIsolate:void 0}):null})]}),t==="graph"&&d.jsxs("div",{className:"graph-wrap","data-testid":"graph-full",style:{height:"100%"},children:[d.jsxs("div",{className:"graph-modes",children:[d.jsxs("div",{className:"seg","aria-label":"Graph scope",children:[d.jsx("button",{type:"button","aria-pressed":b==="review","data-testid":"graph-mode-review",className:b==="review"?"active":"",onClick:()=>E("review"),children:"This review"}),d.jsx("button",{type:"button","aria-pressed":b==="architecture","data-testid":"graph-mode-architecture",className:b==="architecture"?"active":"",onClick:()=>E("architecture"),children:"Indexed architecture"})]}),d.jsxs("div",{className:"legend","aria-hidden":"true",children:[d.jsxs("span",{children:[d.jsx("i",{})," cheap"]}),d.jsxs("span",{children:[d.jsx("i",{className:"exp"})," expensive"]}),d.jsxs("span",{children:[d.jsx("i",{className:"crit"})," critical"]}),d.jsxs("span",{children:[d.jsx("i",{className:"dash"})," inferred"]}),d.jsxs("span",{children:[d.jsx("i",{className:"seed"})," changed"]}),d.jsxs("span",{children:[d.jsx("i",{className:"down"})," downstream"]})]}),d.jsx("button",{type:"button",className:gt?"chip-btn active":"chip-btn","data-testid":"graph-test-overlay","aria-pressed":gt,onClick:()=>{const P=!gt;mt(P),localStorage.setItem("loadpath.testOverlay",P?"1":"0")},children:"Tests"})]}),No.length||b==="review"&&p||g!=null&&g.indexed&&!(re||g!=null&&g.graph_pending)?d.jsx(nc,{nodes:No,edges:gr,onWhatIf:Cn,...sn,...b==="architecture"?{isolateSource:null,onIsolate:void 0,nodeRoles:void 0,testOverlay:!1}:{}}):re||g!=null&&g.graph_pending?d.jsx("p",{className:"empty","data-testid":"graph-loading",children:"Drawing the architecture map…"}):d.jsx("p",{className:"empty","data-testid":"graph-empty",children:"Index the repo or run a review first. Click a node to inspect it."})]}),t==="prs"&&d.jsxs("div",{className:"pr-list","data-testid":"pr-list",children:[d.jsxs("div",{className:"pr-toolbar",children:[d.jsxs("label",{className:"field provider",children:[d.jsx("span",{children:"Provider"}),d.jsxs("select",{"data-testid":"pr-provider",value:z,onChange:P=>It(P.target.value,H,oe),children:[d.jsx("option",{value:"github",children:"GitHub"}),d.jsx("option",{value:"gitlab",children:"GitLab"}),d.jsx("option",{value:"bitbucket",children:"Bitbucket"})]})]}),d.jsxs("label",{className:"field",children:[d.jsx("span",{children:"Repository"}),d.jsx("input",{"data-testid":"pr-repo",placeholder:M.length?"Search your repos":"owner/repo",value:H,onChange:P=>It(z,P.target.value,oe),list:"scm-repos",spellCheck:!1}),d.jsx("datalist",{id:"scm-repos",children:M.map(P=>d.jsxs("option",{value:P.slug,children:[P.private?"private":"public",P.local_path?" · local":""]},P.slug))})]}),d.jsx("button",{type:"button","data-testid":"btn-refresh-repos",className:"btn",disabled:!!j||!_o(z),onClick:()=>{Rt(z)},children:"My repos"}),d.jsx("button",{type:"button","data-testid":"btn-list-prs",className:"btn",disabled:!!j,onClick:So,children:"List PRs"})]}),M.length>0?d.jsxs("p",{className:"muted scm-count","data-testid":"scm-repo-count",children:[M.length," ",z," repositor",M.length===1?"y":"ies",z==="github"&&C.github_user?` · @${String(C.github_user)}`:"",z==="gitlab"&&C.gitlab_user?` · @${String(C.gitlab_user)}`:"",z==="bitbucket"&&C.bitbucket_user?` · ${String(C.bitbucket_user)}`:""]}):null,W.length===0?d.jsxs("div",{className:"empty","data-testid":"pr-empty",children:[d.jsx("h2",{children:"No pull requests loaded"}),d.jsx("p",{children:"Sign in under Settings (or paste a token), load your repositories, then list open PRs. Reviewing a PR fills base and head from its SHAs."})]}):W.map(P=>{var G;return d.jsxs("article",{className:"pr","data-testid":`pr-${P.number}`,children:[d.jsxs("h3",{children:["#",P.number," ",P.title]}),d.jsxs("div",{className:"pr-meta muted",children:[d.jsx("span",{className:`chip ${P.draft?"":"open"}`,children:P.draft?"draft":P.state}),d.jsx("span",{children:P.author}),d.jsxs("span",{children:[P.source_branch," → ",P.target_branch]}),P.loadpath?d.jsxs("span",{className:`chip ${P.loadpath.level||""}`,"data-testid":`pr-loadpath-${P.number}`,children:[((G=P.loadpath.level)==null?void 0:G.toUpperCase())||"REVIEWED",P.loadpath.contract_break&&P.loadpath.contract_break!=="none"?` · ${P.loadpath.contract_break}`:""]}):d.jsx("span",{className:"muted",children:"no Loadpath walk yet"})]}),d.jsxs("div",{className:"pr-actions",children:[d.jsxs("a",{href:P.url,target:"_blank",rel:"noreferrer",children:["Open on ",P.provider]}),d.jsx("button",{type:"button",className:"btn primary","data-testid":`pr-review-${P.number}`,onClick:()=>void fi(P),children:"Review this PR"})]})]},`${P.provider}-${P.number}`)})]}),t==="settings"&&Pe&&d.jsxs("form",{className:"settings","data-testid":"settings-form",onSubmit:hi,children:[d.jsxs("div",{children:[d.jsx("h1",{children:"Settings"}),d.jsx("p",{className:"muted",children:"Tokens stay on this machine in ~/.loadpath/settings.json. AI runs only on residual uncertainty the graph could not close."})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Appearance"}),d.jsx("p",{className:"muted",children:"Local to this browser. High contrast is a first-class theme, not an afterthought."}),d.jsx("div",{className:"theme-grid","data-testid":"theme-grid",children:Qa.map(P=>d.jsxs("button",{type:"button","data-theme":P.id,className:we===P.id?"theme-swatch active":"theme-swatch","data-testid":`theme-${P.id}`,onClick:()=>xo(P.id),children:[d.jsx("div",{className:"swatch-bar","aria-hidden":"true"}),d.jsx("div",{className:"name",children:P.label}),d.jsx("div",{className:"group",children:P.group})]},P.id))})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Editor"}),d.jsx("p",{className:"muted",children:"Open files from the inspector and read-order in Cursor, VS Code, or the system handler."}),d.jsx("label",{htmlFor:"editor-pref",children:"Preferred editor"}),d.jsxs("select",{id:"editor-pref","data-testid":"editor-pref",defaultValue:Em(),onChange:P=>VN(P.target.value),children:[d.jsx("option",{value:"auto",children:"Auto (Cursor, then VS Code)"}),d.jsx("option",{value:"cursor",children:"Cursor"}),d.jsx("option",{value:"vscode",children:"VS Code"}),d.jsx("option",{value:"system",children:"System default"})]})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Source control"}),d.jsx("p",{className:"muted",children:"Sign in with OAuth to list every repository the account can access. Tokens stay in ~/.loadpath/settings.json. A classic PAT still works if you prefer not to register an OAuth app."}),d.jsxs("div",{className:"scm-login","data-testid":"scm-github",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitHub"}),d.jsx("p",{className:"muted",children:C.github_token_set?C.github_user?`Signed in as @${String(C.github_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.github_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-github-disconnect",onClick:()=>void yt("github"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-github-login",disabled:!!dt||!C.github_oauth_ready,onClick:()=>void hr(),children:dt?"Waiting for GitHub…":"Sign in with GitHub"})})]}),dt?d.jsxs("p",{className:"oauth-code","data-testid":"github-user-code",children:["Enter ",d.jsx("code",{children:dt.user_code})," at GitHub if the browser did not fill it in."]}):null,C.github_oauth_ready?null:d.jsx("p",{className:"muted",children:"Sign-in needs a GitHub OAuth App with Device Flow enabled. Set LOADPATH_GITHUB_CLIENT_ID or paste the client ID below."}),d.jsx("label",{htmlFor:"github_oauth_client_id",children:"GitHub OAuth client ID"}),d.jsx("input",{id:"github_oauth_client_id",name:"github_oauth_client_id","data-testid":"github-oauth-client-id",placeholder:"Ov23…",defaultValue:String(C.github_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"github_token",children:"GitHub token (optional PAT)"}),d.jsx("input",{id:"github_token",name:"github_token",type:"password",placeholder:"ghp_…",autoComplete:"off"}),d.jsx("label",{htmlFor:"github_host",children:"GitHub host (Enterprise)"}),d.jsx("input",{id:"github_host",name:"github_host","data-testid":"github-host",placeholder:"github.com",defaultValue:String(C.github_host||""),autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-gitlab",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"GitLab"}),d.jsx("p",{className:"muted",children:C.gitlab_token_set?C.gitlab_user?`Signed in as @${String(C.gitlab_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.gitlab_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-gitlab-disconnect",onClick:()=>void yt("gitlab"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-gitlab-login",disabled:Wn||!C.gitlab_oauth_ready,onClick:()=>void ko(),children:Wn?"Waiting for GitLab…":"Sign in with GitLab"})})]}),d.jsx("label",{htmlFor:"gitlab_host",children:"GitLab host"}),d.jsx("input",{id:"gitlab_host",name:"gitlab_host","data-testid":"gitlab-host",placeholder:"gitlab.com",defaultValue:String(C.gitlab_host||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_id",children:"GitLab OAuth application ID"}),d.jsx("input",{id:"gitlab_oauth_client_id",name:"gitlab_oauth_client_id","data-testid":"gitlab-oauth-client-id",defaultValue:String(C.gitlab_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_oauth_client_secret",children:"GitLab OAuth secret"}),d.jsx("input",{id:"gitlab_oauth_client_secret",name:"gitlab_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"gitlab_token",children:"GitLab token (optional PAT)"}),d.jsx("input",{id:"gitlab_token",name:"gitlab_token",type:"password",placeholder:"glpat-…",autoComplete:"off"}),d.jsxs("div",{className:"scm-login","data-testid":"scm-bitbucket",children:[d.jsxs("div",{children:[d.jsx("strong",{children:"Bitbucket"}),d.jsx("p",{className:"muted",children:C.bitbucket_token_set?C.bitbucket_user?`Signed in as ${String(C.bitbucket_user)}`:"Token saved on this machine":"Not connected"})]}),d.jsx("div",{className:"btn-row",children:C.bitbucket_token_set?d.jsx("button",{type:"button",className:"btn","data-testid":"btn-bitbucket-disconnect",onClick:()=>void yt("bitbucket"),children:"Disconnect"}):d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-bitbucket-login",disabled:Vn||!C.bitbucket_oauth_ready,onClick:()=>void di(),children:Vn?"Waiting for Bitbucket…":"Sign in with Bitbucket"})})]}),C.bitbucket_oauth_ready?null:d.jsxs("p",{className:"muted",children:["Sign-in needs a Bitbucket OAuth consumer (key + secret). Callback URL:"," ",d.jsx("code",{children:"/api/oauth/bitbucket/callback"})," on this app origin."]}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_id",children:"Bitbucket OAuth key"}),d.jsx("input",{id:"bitbucket_oauth_client_id",name:"bitbucket_oauth_client_id","data-testid":"bitbucket-oauth-client-id",defaultValue:String(C.bitbucket_oauth_client_id||""),autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_oauth_client_secret",children:"Bitbucket OAuth secret"}),d.jsx("input",{id:"bitbucket_oauth_client_secret",name:"bitbucket_oauth_client_secret",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_token",children:"Bitbucket token (optional app password)"}),d.jsx("input",{id:"bitbucket_token",name:"bitbucket_token",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"bitbucket_username",children:"Bitbucket username (app passwords)"}),d.jsx("input",{id:"bitbucket_username",name:"bitbucket_username",defaultValue:String(C.bitbucket_username||"")})]}),d.jsxs("section",{className:"settings-card",children:[d.jsx("h2",{children:"Residual AI"}),d.jsx("label",{htmlFor:"ai_provider",children:"Provider"}),d.jsxs("select",{id:"ai_provider",name:"ai_provider",defaultValue:String(((an=C.ai)==null?void 0:an.provider)||"none"),children:[d.jsx("option",{value:"none",children:"none (graph only)"}),d.jsx("option",{value:"anthropic",children:"Anthropic"}),d.jsx("option",{value:"openai",children:"OpenAI"}),d.jsx("option",{value:"grok",children:"Grok / xAI"}),d.jsx("option",{value:"deepseek",children:"DeepSeek"}),d.jsx("option",{value:"cursor",children:"Cursor-compatible (OpenAI protocol)"}),d.jsx("option",{value:"ollama",children:"Ollama local"})]}),d.jsx("label",{htmlFor:"ai_api_key",children:"API key"}),d.jsx("input",{id:"ai_api_key",name:"ai_api_key",type:"password",autoComplete:"off"}),d.jsx("label",{htmlFor:"ai_model",children:"Model"}),d.jsx("input",{id:"ai_model",name:"ai_model","data-testid":"ai-model",placeholder:"optional override",defaultValue:String(((ln=C.ai)==null?void 0:ln.model)||"")}),d.jsx("label",{htmlFor:"ai_base_url",children:"Base URL"}),d.jsx("input",{id:"ai_base_url",name:"ai_base_url","data-testid":"ai-base-url",placeholder:"optional, OpenAI-compatible",defaultValue:String(((un=C.ai)==null?void 0:un.base_url)||"")}),d.jsx("button",{className:"btn primary",type:"submit","data-testid":"btn-save-settings",children:"Save"})]})]})]})]}),d.jsx(x0,{open:nt,actions:Kn,onClose:()=>lt(!1)}),je?d.jsx(KN,{initialPath:o,onClose:()=>Le(!1),onSelect:P=>{if(Ze.current){w("Wait for the current job to finish before switching workspace.");return}Le(!1),Br(P)}}):null]})}function ij({review:t,findings:r,aiNote:o,busy:s,tourIndex:a,onTour:u,onAskAi:c,onCopy:h,onPost:p,onSelect:y,onOpenFile:x,onExport:v,history:g,diff:_,onReopen:S,onWaiver:N}){var E,I,w,j,A,$,F,Y,q,re,J,te,Q,C,V,W,U;const b=[...new Set(t.confidence.reasons||[])];return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:`merge-box ${t.confidence.level}`,children:[d.jsxs("div",{className:`level ${t.confidence.level}`,children:[t.confidence.level.toUpperCase()," — ",t.title]}),b.length?d.jsx("ul",{className:"reasons",children:b.map(M=>d.jsx("li",{children:M},M))}):null,t.what_if?d.jsx("span",{className:"chip whatif","data-testid":"whatif-chip",children:"what-if"}):null,t.low_risk?d.jsx("span",{className:"chip",children:"low-risk"}):null,t.change_kinds.map(M=>d.jsx("span",{className:"chip",children:ns(M)},M)),(E=t.contract_break)!=null&&E.kind&&t.contract_break.kind!=="none"?d.jsxs("span",{className:`chip ${t.contract_break.kind==="breaking"?"blocker":""}`,"data-testid":"contract-kind",children:["contract ",t.contract_break.kind]}):null]}),d.jsxs("div",{className:"metrics",children:[d.jsxs("div",{className:"metric",children:[d.jsxs("div",{className:"n",children:[t.confidence.covered_sinks,"/",t.confidence.sinks]}),d.jsx("div",{className:"l",children:"Sinks tested"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:r.length}),d.jsx("div",{className:"l",children:"Findings"})]}),d.jsxs("div",{className:"metric",children:[d.jsx("div",{className:"n",children:t.residuals.length}),d.jsx("div",{className:"l",children:"Residuals"})]})]}),d.jsx("pre",{className:"headline",children:t.headline}),(t.checklist||[]).length?d.jsxs("details",{className:"section",open:!0,"data-testid":"merge-checklist",children:[d.jsxs("summary",{children:["Merge checklist"," ",d.jsx("span",{className:"count",children:(t.checklist||[]).filter(M=>M.status==="todo").length})]}),(t.checklist||[]).map(M=>d.jsxs("div",{className:`check-item ${M.status}`,children:[d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.status}`,children:M.status}),M.title]}),M.detail?d.jsx("div",{className:"why",children:M.detail}):null,M.body?d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body||"")},children:"Copy test"}):null,M.kind==="finding"&&M.status==="todo"&&M.rule?d.jsx("button",{type:"button",className:"btn",onClick:()=>N(M.rule,M.node_id),children:"Waive in loadpath.yml"}):null]},M.id))]}):null,t.index?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Index ",d.jsx("span",{className:"count",children:t.index.counts.nodes})]}),d.jsxs("div",{className:"muted",children:["Walked ",t.index.counts.nodes," nodes / ",t.index.counts.edges," edges",t.index.reindex_skipped?" from an unchanged index":t.index.reindexed?" after an incremental refresh":" from the existing index",t.index.django_boot&&t.index.django_boot!=="off"?` · Django boot ${t.index.django_boot}`:"",(I=t.workspace)!=null&&I.three_dot?" · three-dot range":""]})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Read this ",d.jsx("span",{className:"count",children:t.read_order.length})]}),t.read_order.map((M,D)=>d.jsxs("div",{className:D===a?"read-item tour-current":"read-item",children:[d.jsxs("button",{type:"button",className:"linkish file",onClick:()=>u(D),children:[D+1,". ",M.path]}),d.jsx("div",{className:"why",children:M.why}),d.jsx("button",{type:"button",className:"btn",onClick:()=>x(M.path),children:"Open"})]},M.path)),t.read_order.length>0?d.jsxs("div",{className:"btn-row tour-row",children:[d.jsx("button",{type:"button",className:"btn","data-testid":"btn-tour-prev",disabled:a<=0,onClick:()=>u(Math.max(0,a-1)),children:"Previous"}),d.jsx("button",{type:"button",className:"btn primary","data-testid":"btn-tour-next",disabled:a>=t.read_order.length-1,onClick:()=>u(Math.min(t.read_order.length-1,a+1)),children:"Next in read order"}),d.jsxs("span",{className:"muted",children:[a+1,"/",t.read_order.length]})]}):null]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Clusters ",d.jsx("span",{className:"count",children:t.clusters.length})]}),t.clusters.map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:M.title})," — ",M.files.join(", ")]},M.id))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Architecture ",d.jsx("span",{className:"count",children:r.length})]}),r.length===0?d.jsx("div",{className:"muted",children:t.architecture_note}):r.map(M=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>M.node_id&&y(M.node_id),children:[d.jsx("span",{className:`chip ${M.severity}`,children:M.severity}),M.message]})},M.rule+M.message))]}),d.jsx(Im,{cards:t.deepening}),(j=(w=t.contract_break)==null?void 0:w.reasons)!=null&&j.length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Contract ",d.jsx("span",{className:"count",children:t.contract_break.kind})]}),t.contract_break.reasons.map(M=>d.jsx("div",{className:"muted",children:M},M)),($=(A=t.contract_break.sides)==null?void 0:A.rows)!=null&&$.length?d.jsxs("table",{className:"type-table","data-testid":"contract-sides",children:[d.jsx("thead",{children:d.jsxs("tr",{children:[d.jsx("th",{children:"Field"}),d.jsx("th",{children:"Serializer"}),d.jsx("th",{children:"Zod"}),d.jsx("th",{children:"GraphQL"})]})}),d.jsx("tbody",{children:t.contract_break.sides.rows.map(M=>d.jsxs("tr",{className:M.status,children:[d.jsx("td",{children:M.field}),d.jsx("td",{children:M.serializer?"yes":"—"}),d.jsx("td",{children:M.zod?"yes":"—"}),d.jsx("td",{children:M.graphql?"yes":"—"})]},M.field))})]}):null]}):null,(F=t.auth)!=null&&F.note?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Auth"}),d.jsx("div",{className:"muted",children:t.auth.note}),(t.auth.missing_permissions||[]).map(M=>d.jsxs("div",{className:"finding",children:[d.jsx("span",{className:"chip warning",children:"missing"}),M.name]},M.id))]}):null,(t.suggested_tests||[]).length?d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Suggested tests ",d.jsx("span",{className:"count",children:(Y=t.suggested_tests)==null?void 0:Y.length})]}),(t.suggested_tests||[]).map(M=>d.jsxs("div",{className:"residual",children:[d.jsx("strong",{children:M.title}),d.jsx("pre",{className:"headline",children:M.body}),d.jsx("button",{type:"button",className:"btn",onClick:()=>{navigator.clipboard.writeText(M.body)},children:"Copy sketch"})]},M.title))]}):null,(q=t.trend)!=null&&q.note?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Confidence trend"}),d.jsx("div",{className:"muted",children:t.trend.note}),(t.trend.points||[]).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[M.level," · ",ic(M.created_at),M.sinks!=null?` · ${M.sinks} sinks`:""]},M.id))]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Residual ",d.jsx("span",{className:"count",children:t.residuals.length})]}),d.jsx("p",{className:"muted",children:"AI is only used here, on what the graph could not close."}),t.residuals.map(M=>d.jsx("div",{className:"residual muted",children:M},M))]}),g.length?d.jsxs("details",{className:"section","data-testid":"review-history",children:[d.jsxs("summary",{children:["History ",d.jsx("span",{className:"count",children:g.length})]}),_?d.jsx("div",{className:"muted",children:_.note}):null,g.slice(0,12).map(M=>d.jsxs("button",{type:"button",className:M.id===t.id?"history-item current":"history-item",onClick:()=>S(M.id),children:[d.jsx("span",{className:`chip ${M.level||""}`,children:M.level||"walk"}),M.title||M.id.slice(0,8),d.jsx("span",{className:"muted",children:M.created_at?ic(M.created_at):""})]},M.id))]}):null,(J=(re=t.evolution)==null?void 0:re.notes)!=null&&J.length||(Q=(te=t.evolution)==null?void 0:te.hotspots)!=null&&Q.some(M=>M.commits)?d.jsxs("details",{className:"section",children:[d.jsx("summary",{children:"Churn & coupling"}),(((C=t.evolution)==null?void 0:C.notes)||[]).map(M=>d.jsx("div",{className:"muted",children:M},M)),(((V=t.evolution)==null?void 0:V.hotspots)||[]).filter(M=>M.commits).slice(0,6).map(M=>d.jsxs("div",{className:"muted",children:[d.jsx("span",{className:"file",children:M.path})," — ",M.commits," commits, bus factor ",M.bus_factor]},M.path))]}):null,d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:s,onClick:c,children:"Ask configured model"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-copy-markdown",onClick:h,children:"Copy markdown"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-export-html",onClick:v,children:"Save HTML"}),d.jsx("button",{type:"button",className:"btn","data-testid":"btn-post-comment",disabled:s||!!t.what_if,title:t.what_if?"Hypothetical walks are not posted to a pull request":void 0,onClick:p,children:"Post to PR"})]}),o?d.jsx("pre",{className:"headline",children:o}):null,d.jsx("div",{className:"kicker",children:"Reviewers"}),d.jsx("div",{className:"muted",children:t.suggested_reviewers.join(", ")||"—"}),(W=t.codeowners_reviewers)!=null&&W.length?d.jsxs("div",{className:"muted",children:["CODEOWNERS: ",t.codeowners_reviewers.join(", ")]}):null,(U=t.knowledge_owners)!=null&&U.length?d.jsxs("div",{className:"muted",children:["Knowledge: ",t.knowledge_owners.join(", ")]}):null]})}function sj({architecture:t,busy:r,onReindex:o,onReview:s,onSelect:a,config:u,health:c,onSaveConfig:h,onWaiver:p}){var x;const y=t.findings.filter(v=>!v.waived);return d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"merge-box high",children:[d.jsxs("div",{className:"level high",children:["INDEXED — ",t.counts.nodes," nodes"]}),d.jsxs("div",{className:"muted",style:{marginTop:8},children:[t.indexed_at?`Last index ${ic(t.indexed_at)}`:"Indexed",t.incremental?" · incremental":" · full",t.stale?" · stale":"",t.django_boot&&t.django_boot!=="off"?` · Django boot ${t.django_boot}`:""]}),d.jsxs("span",{className:"chip",children:[t.counts.edges," edges"]}),t.has_config?d.jsx("span",{className:"chip",children:"loadpath.yml"}):null]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Bounded contexts"}),Object.values(t.contexts).map(v=>d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v.name})," — ",(v.django_apps||[]).join(", ")||"no apps"," ·"," ",(v.owners||[]).join(", ")||"unowned"]},v.name))]}),d.jsxs("details",{className:"section",children:[d.jsxs("summary",{children:["Rules ",d.jsx("span",{className:"count",children:(t.rules||[]).length})]}),(t.rules||[]).map(v=>d.jsx("div",{className:"muted",children:v},v))]}),d.jsxs("details",{className:"section",open:!0,children:[d.jsxs("summary",{children:["Findings ",d.jsx("span",{className:"count",children:y.length})]}),y.length===0?d.jsx("div",{className:"muted",children:"No architecture rule hits on the full graph."}):y.map(v=>d.jsx("div",{className:"finding",children:d.jsxs("button",{type:"button",className:"linkish",onClick:()=>v.node_id&&a(v.node_id),children:[d.jsx("span",{className:`chip ${v.severity}`,children:v.severity}),v.message]})},v.rule+v.message))]}),d.jsx(Im,{cards:t.deepening}),(x=c==null?void 0:c.points)!=null&&x.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"architecture-health",children:[d.jsxs("summary",{children:["Health over time ",d.jsx("span",{className:"count",children:c.points.length})]}),d.jsx("div",{className:"sparkline","aria-hidden":"true",children:c.points.map(v=>d.jsx("i",{className:v.level||"",title:`${v.level} · ${v.findings} findings`,style:{height:`${8+Math.min(24,(v.findings||0)*4)}px`}},v.id||v.created_at))}),Object.entries(c.contexts).map(([v,g])=>{var _;return d.jsxs("div",{className:"muted",children:[d.jsx("strong",{children:v})," — last ",((_=g[g.length-1])==null?void 0:_.findings)??0," findings"]},v)})]}):null,u?d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"loadpath.yml"}),d.jsx(w0,{config:u,busy:r,onSave:h,onWaiver:p})]}):null,d.jsxs("details",{className:"section",open:!0,children:[d.jsx("summary",{children:"Types"}),d.jsx("table",{className:"type-table",children:d.jsx("tbody",{children:Object.entries(t.type_counts||{}).sort((v,g)=>g[1]-v[1]).slice(0,12).map(([v,g])=>d.jsxs("tr",{children:[d.jsx("td",{children:li(v)}),d.jsx("td",{children:g})]},v))})})]}),d.jsxs("div",{className:"btn-row",children:[d.jsx("button",{type:"button",className:"btn",disabled:r,onClick:o,"data-testid":"btn-full-reindex",children:"Full reindex"}),d.jsx("button",{type:"button",className:"btn primary",disabled:r,onClick:s,children:"Review against this index"})]})]})}function Im({cards:t}){const r=t||[];return r.length?d.jsxs("details",{className:"section",open:!0,"data-testid":"deepening-list",children:[d.jsxs("summary",{children:["Depth ",d.jsx("span",{className:"count",children:r.length})]}),d.jsx("p",{className:"muted",children:"Deepening opportunities: more behaviour behind a smaller interface, at a real seam."}),r.map(o=>d.jsxs("div",{className:"finding","data-testid":"deepening-card",children:[d.jsx("span",{className:`chip ${o.strength}`,children:_0(o.strength)}),o.top?d.jsx("span",{className:"chip",children:"top"}):null,d.jsx("strong",{children:o.title}),d.jsx("div",{className:"why",children:o.message}),o.deletion_test?d.jsxs("div",{className:"muted",children:["Deletion test: ",o.deletion_test]}):null,o.before&&o.after?d.jsxs("div",{className:"muted",children:[o.before," → ",o.after]}):null]},o.rule+o.title))]}):null}Pm(Mm());m0.createRoot(document.getElementById("root")).render(d.jsx(L.StrictMode,{children:d.jsx(oj,{})}));export{Kk as L,uj as a,aj as c,d as j,lj as l,L as r,li as t}; diff --git a/src/loadpath/static/index.html b/src/loadpath/static/index.html index d829347..7be3fd3 100644 --- a/src/loadpath/static/index.html +++ b/src/loadpath/static/index.html @@ -17,7 +17,7 @@ - + diff --git a/tests/e2e/test_ui_flows.py b/tests/e2e/test_ui_flows.py index 6132a0f..e577304 100644 --- a/tests/e2e/test_ui_flows.py +++ b/tests/e2e/test_ui_flows.py @@ -206,8 +206,6 @@ def test_ui_index_review_graph_copy_and_workspace(live_app, browser_page): @pytest.mark.playwright def test_ui_index_polls_progress_endpoint(live_app, browser_page): - import time - base_url, repo = live_app page = browser_page page.goto(base_url, wait_until="networkidle") @@ -223,10 +221,6 @@ def on_route(route): progress_hits.append(url) route.continue_() return - if req.method == "POST" and url.rstrip("/").endswith("/api/index"): - time.sleep(1.2) - route.continue_() - return route.continue_() page.route("**/api/**", on_route) @@ -239,9 +233,9 @@ def on_route(route): page.wait_for_function( """() => { const t = document.querySelector('.rail-foot .muted')?.textContent || ''; - return /Extract|Scan|Stitch|Indexed|Boot|Hashed/.test(t); + return /Extract|Scan|Stitch|Indexed|Boot|Hashed|Indexing/.test(t); }""", - timeout=10_000, + timeout=20_000, ) page.screenshot(path="/opt/cursor/artifacts/index_progress_bar.png") page.get_by_test_id("architecture-brief").locator(".level").wait_for(timeout=15_000) diff --git a/tests/unit/test_django_extractors.py b/tests/unit/test_django_extractors.py index 9964f65..e3e3bf8 100644 --- a/tests/unit/test_django_extractors.py +++ b/tests/unit/test_django_extractors.py @@ -794,6 +794,29 @@ def test_extracts_permission_class_and_dataclass_service(): assert any("test_viewer_access" in d for d in dsts) +def test_view_permission_classes_share_id_with_permission_class(): + perm_file = extract_django_file( + "backend/billing/permissions.py", + "from rest_framework.permissions import BasePermission\n" + "class InvoicePermission(BasePermission):\n" + " def has_permission(self, request, view):\n" + " return True\n", + _cfg(), + ) + view_file = extract_django_file( + "backend/billing/views.py", + "from rest_framework.viewsets import ModelViewSet\n" + "class InvoiceViewSet(ModelViewSet):\n" + " permission_classes = [InvoicePermission, IsAuthenticated]\n", + _cfg(), + ) + class_ids = {n.id for n in perm_file.nodes if n.type is NodeType.PERMISSION} + view_ids = {n.id for n in view_file.nodes if n.type is NodeType.PERMISSION} + assert "django.permission:billing.InvoicePermission" in class_ids + assert "django.permission:billing.InvoicePermission" in view_ids + assert "django.permission:IsAuthenticated" in view_ids + + def test_dataclass_in_tests_is_not_a_service(): source = ( "from dataclasses import dataclass\n" diff --git a/ui/src/App.tsx b/ui/src/App.tsx index f5d84b5..7eaf494 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1445,7 +1445,7 @@ export function App() { Tests
- {graphNodes.length || review || architecture?.indexed ? ( + {graphNodes.length || (graphMode === "review" && review) || (architecture?.indexed && !(graphLoading || architecture?.graph_pending)) ? (