add new agent components

This commit is contained in:
Abdelrahman Abdallah
2026-04-02 21:12:48 +02:00
parent bf808572d3
commit 2c6763eb08
19 changed files with 6183 additions and 296 deletions
+154
View File
@@ -0,0 +1,154 @@
from __future__ import annotations
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any
MAX_PLUGIN_LINES = 12
MAX_PLUGIN_PREVIEW_CHARS = 4000
@dataclass(frozen=True)
class PluginCacheEntry:
name: str
enabled: bool = True
version: str | None = None
source: str | None = None
def load_plugin_cache_summary(
cwd: Path,
additional_working_directories: tuple[str, ...] = (),
) -> str | None:
snapshot = discover_plugin_cache(cwd, additional_working_directories)
if snapshot is None:
return None
return snapshot
def discover_plugin_cache(
cwd: Path,
additional_working_directories: tuple[str, ...] = (),
) -> str | None:
for path in _discover_candidate_paths(cwd, additional_working_directories):
try:
payload = json.loads(path.read_text(encoding='utf-8'))
except (OSError, json.JSONDecodeError):
continue
entries = _extract_entries(payload)
if not entries:
continue
lines = [
f'Plugin cache loaded from: {path}',
f'Plugin entries discovered: {len(entries)}',
]
enabled = [entry for entry in entries if entry.enabled]
disabled = [entry for entry in entries if not entry.enabled]
lines.append(f'Enabled plugins: {len(enabled)}')
if disabled:
lines.append(f'Disabled plugins: {len(disabled)}')
for entry in entries[:MAX_PLUGIN_LINES]:
details = [entry.name]
if entry.version:
details.append(f'version={entry.version}')
if entry.source:
details.append(f'source={entry.source}')
if not entry.enabled:
details.append('disabled')
lines.append(f"- {'; '.join(details)}")
if len(entries) > MAX_PLUGIN_LINES:
lines.append(f'- ... plus {len(entries) - MAX_PLUGIN_LINES} more plugin entries')
rendered = '\n'.join(lines)
if len(rendered) > MAX_PLUGIN_PREVIEW_CHARS:
rendered = rendered[: MAX_PLUGIN_PREVIEW_CHARS - 3] + '...'
return rendered
return None
def _discover_candidate_paths(
cwd: Path,
additional_working_directories: tuple[str, ...],
) -> list[Path]:
candidates: list[Path] = []
seen: set[Path] = set()
relative_paths = (
'.port_sessions/plugin_cache.json',
'.port_sessions/plugins.json',
'.claude/plugins/cache.json',
'.claw/plugins/cache.json',
'plugins/cache.json',
'.plugins/cache.json',
)
def remember(path: Path) -> None:
resolved = path.resolve()
if resolved in seen or not resolved.exists() or not resolved.is_file():
return
seen.add(resolved)
candidates.append(resolved)
for root in _walk_upwards(cwd.resolve()):
for relative in relative_paths:
remember(root / relative)
for raw_path in additional_working_directories:
directory = Path(raw_path).resolve()
for relative in relative_paths:
remember(directory / relative)
return candidates
def _walk_upwards(path: Path) -> list[Path]:
current = path
walked: list[Path] = []
while True:
walked.append(current)
if current.parent == current:
break
current = current.parent
return walked
def _extract_entries(payload: Any) -> list[PluginCacheEntry]:
entries: list[PluginCacheEntry] = []
raw_entries: list[Any] = []
if isinstance(payload, list):
raw_entries = payload
elif isinstance(payload, dict):
if isinstance(payload.get('plugins'), list):
raw_entries = payload['plugins']
elif isinstance(payload.get('entries'), list):
raw_entries = payload['entries']
else:
raw_entries = [
{'name': key, **value}
for key, value in payload.items()
if isinstance(value, dict)
]
for item in raw_entries:
entry = _coerce_entry(item)
if entry is not None:
entries.append(entry)
return entries
def _coerce_entry(item: Any) -> PluginCacheEntry | None:
if isinstance(item, str) and item.strip():
return PluginCacheEntry(name=item.strip())
if not isinstance(item, dict):
return None
name = item.get('name') or item.get('plugin') or item.get('id')
if not isinstance(name, str) or not name.strip():
return None
source = item.get('source') or item.get('path') or item.get('module')
version = item.get('version')
enabled = item.get('enabled')
return PluginCacheEntry(
name=name.strip(),
enabled=True if enabled is None else bool(enabled),
version=version if isinstance(version, str) and version else None,
source=source if isinstance(source, str) and source else None,
)