agr-opentui 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ """OpenTUI bridge package for agr."""
agr_opentui/bridge.py ADDED
@@ -0,0 +1,157 @@
1
+ """JSON bridge for the OpenTUI interface."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+
10
+ from agr.config import AgrConfig, Dependency, find_config, find_repo_root
11
+ from agr.fetcher import get_installed_skills
12
+ from agr.handle import ParsedHandle, parse_handle
13
+ from agr.skill import SKILL_MARKER
14
+ from agr.tool import get_tool
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class BridgeDependency:
19
+ identifier: str
20
+ handle: str | None
21
+ path: str | None
22
+ is_local: bool
23
+ display: str
24
+ candidates: list[str]
25
+ candidates_by_tool: dict[str, list[str]]
26
+ installed: bool
27
+ skill_md_path: str | None
28
+
29
+
30
+ def _parse_dependency(dep: Dependency) -> ParsedHandle:
31
+ if dep.handle:
32
+ return parse_handle(dep.handle, prefer_local=False)
33
+ if dep.path:
34
+ path = Path(dep.path)
35
+ return ParsedHandle(is_local=True, name=path.name, local_path=path)
36
+ raise ValueError("Dependency missing handle/path")
37
+
38
+
39
+ def _candidates_for_install(handle: ParsedHandle, tool_name: str) -> list[str]:
40
+ tool = get_tool(tool_name)
41
+ candidates = [
42
+ handle.to_skill_path(tool).as_posix(),
43
+ handle.name,
44
+ handle.to_installed_name(),
45
+ ]
46
+ if handle.is_local:
47
+ candidates.append(f"local/{handle.name}")
48
+ return list(dict.fromkeys(candidates))
49
+
50
+
51
+ def _installed_by_tool(repo_root: Path, tools: list[str]) -> dict[str, list[str]]:
52
+ installed: dict[str, list[str]] = {}
53
+ for tool in tools:
54
+ try:
55
+ installed[tool] = get_installed_skills(repo_root, get_tool(tool))
56
+ except Exception:
57
+ installed[tool] = []
58
+ return installed
59
+
60
+
61
+ def _resolve_skill_md_path(
62
+ dep: Dependency,
63
+ *,
64
+ handle: ParsedHandle,
65
+ repo_root: Path | None,
66
+ default_tool: str | None,
67
+ ) -> str | None:
68
+ if repo_root is None:
69
+ return None
70
+
71
+ if dep.path:
72
+ path = Path(dep.path)
73
+ if not path.is_absolute():
74
+ path = repo_root / path
75
+ skill_md = path / SKILL_MARKER
76
+ return str(skill_md) if skill_md.exists() else None
77
+
78
+ if not default_tool:
79
+ return None
80
+
81
+ tool = get_tool(default_tool)
82
+ skills_dir = tool.get_skills_dir(repo_root)
83
+ candidates = _candidates_for_install(handle, default_tool)
84
+ for candidate in candidates:
85
+ skill_md = skills_dir / candidate / SKILL_MARKER
86
+ if skill_md.exists():
87
+ return str(skill_md)
88
+ return None
89
+
90
+
91
+ def build_payload() -> dict[str, object]:
92
+ repo_root = find_repo_root()
93
+ config_path = find_config()
94
+ config = AgrConfig.load(config_path) if config_path else AgrConfig()
95
+
96
+ tool_names = list(config.tools)
97
+ default_tool = config.default_tool or (tool_names[0] if tool_names else None)
98
+
99
+ installed = (
100
+ _installed_by_tool(repo_root, tool_names) if repo_root and tool_names else {}
101
+ )
102
+
103
+ deps_payload: list[dict[str, object]] = []
104
+ for dep in config.dependencies:
105
+ handle = _parse_dependency(dep)
106
+ candidates = (
107
+ _candidates_for_install(handle, default_tool)
108
+ if default_tool
109
+ else []
110
+ )
111
+ candidates_by_tool = {
112
+ tool_name: _candidates_for_install(handle, tool_name)
113
+ for tool_name in tool_names
114
+ }
115
+ installed_names = installed.get(default_tool or "", [])
116
+ is_installed = any(name in installed_names for name in candidates)
117
+ skill_md_path = _resolve_skill_md_path(
118
+ dep,
119
+ handle=handle,
120
+ repo_root=repo_root,
121
+ default_tool=default_tool,
122
+ )
123
+
124
+ deps_payload.append(
125
+ BridgeDependency(
126
+ identifier=dep.identifier,
127
+ handle=dep.handle,
128
+ path=dep.path,
129
+ is_local=dep.is_local,
130
+ display=dep.identifier,
131
+ candidates=candidates,
132
+ candidates_by_tool=candidates_by_tool,
133
+ installed=is_installed,
134
+ skill_md_path=skill_md_path,
135
+ ).__dict__
136
+ )
137
+
138
+ return {
139
+ "repo_root": str(repo_root) if repo_root else None,
140
+ "config_path": str(config_path) if config_path else None,
141
+ "tools": tool_names,
142
+ "default_tool": default_tool,
143
+ "dependencies": deps_payload,
144
+ "installed": installed,
145
+ }
146
+
147
+
148
+ def main() -> None:
149
+ parser = argparse.ArgumentParser(description="OpenTUI data bridge")
150
+ parser.parse_args()
151
+
152
+ payload = build_payload()
153
+ print(json.dumps(payload))
154
+
155
+
156
+ if __name__ == "__main__":
157
+ main()
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: agr-opentui
3
+ Version: 0.2.0
4
+ Summary: OpenTUI frontend for agr
5
+ Requires-Python: >=3.14.3
6
+ Requires-Dist: agr>=0.7.4
@@ -0,0 +1,5 @@
1
+ agr_opentui/__init__.py,sha256=noLIoaeF0mg3fcx2LNZjDFKGS7ioA-FDCxKLIdM0v8w,38
2
+ agr_opentui/bridge.py,sha256=NmhjSq8jSvxttue0iHV8F484pfaCDMXaVlWz3qTugZw,4551
3
+ agr_opentui-0.2.0.dist-info/METADATA,sha256=2U-qiHJ1mmimS4uVQ_MdwdPGHWUJubMoUIk4tJTkGWo,141
4
+ agr_opentui-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
5
+ agr_opentui-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any