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.
agr_opentui/__init__.py
ADDED
|
@@ -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,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,,
|