ghost-reader 0.1.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.
Files changed (39) hide show
  1. ghost_reader/.release-version +1 -0
  2. ghost_reader/__init__.py +3 -0
  3. ghost_reader/agent_loader.py +64 -0
  4. ghost_reader/cli.py +1124 -0
  5. ghost_reader/constants.py +75 -0
  6. ghost_reader/defaults/__init__.py +1 -0
  7. ghost_reader/defaults/personas/__init__.py +1 -0
  8. ghost_reader/defaults/personas/dex.yaml +30 -0
  9. ghost_reader/defaults/personas/elena.yaml +30 -0
  10. ghost_reader/defaults/personas/mara.yaml +30 -0
  11. ghost_reader/defaults/personas/pip.yaml +30 -0
  12. ghost_reader/defaults/personas/rook.yaml +30 -0
  13. ghost_reader/defaults/templates/__init__.py +1 -0
  14. ghost_reader/defaults/templates/blog-review.html +384 -0
  15. ghost_reader/defaults/templates/report.html +1293 -0
  16. ghost_reader/dialogue.py +283 -0
  17. ghost_reader/errors.py +2 -0
  18. ghost_reader/feedback_store.py +56 -0
  19. ghost_reader/io.py +59 -0
  20. ghost_reader/models.py +227 -0
  21. ghost_reader/paths.py +68 -0
  22. ghost_reader/project.py +277 -0
  23. ghost_reader/release.py +56 -0
  24. ghost_reader/report.py +264 -0
  25. ghost_reader/reviews.py +89 -0
  26. ghost_reader/revision.py +165 -0
  27. ghost_reader/round.py +155 -0
  28. ghost_reader/server.py +282 -0
  29. ghost_reader/sync.py +115 -0
  30. ghost_reader/telemetry.py +111 -0
  31. ghost_reader/time.py +20 -0
  32. ghost_reader/validators.py +66 -0
  33. ghost_reader/verify.py +255 -0
  34. ghost_reader-0.1.0.dist-info/METADATA +221 -0
  35. ghost_reader-0.1.0.dist-info/RECORD +39 -0
  36. ghost_reader-0.1.0.dist-info/WHEEL +5 -0
  37. ghost_reader-0.1.0.dist-info/entry_points.txt +2 -0
  38. ghost_reader-0.1.0.dist-info/licenses/LICENSE +21 -0
  39. ghost_reader-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,3 @@
1
+ """Ghost Reader local-first CLI package."""
2
+
3
+ __version__ = "0.2.3"
@@ -0,0 +1,64 @@
1
+ """Load agent YAML definitions for Ghost Reader personas."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ import yaml
7
+
8
+
9
+ def discover_agent_personas(home: Path) -> list[str]:
10
+ """Scan agents/ directory for *.agent.yaml files and extract persona IDs."""
11
+ agents_dir = home / "agents"
12
+ persona_ids: list[str] = []
13
+ if agents_dir.exists():
14
+ for f in sorted(agents_dir.glob("*.agent.yaml")):
15
+ try:
16
+ raw = f.read_text(encoding="utf-8")
17
+ agent = yaml.safe_load(raw)
18
+ pid = (agent.get("metadata") or {}).get("persona_id")
19
+ if pid:
20
+ persona_ids.append(pid)
21
+ except (yaml.YAMLError, OSError, AttributeError):
22
+ continue
23
+ return persona_ids or _legacy_personas()
24
+
25
+
26
+ def _legacy_personas() -> list[str]:
27
+ """Fallback to hardcoded persona list when no agent YAML files found."""
28
+ return ["mara", "dex", "pip", "elena", "rook"]
29
+
30
+
31
+ def load_agent_yaml(home: Path, persona_id: str) -> Optional[dict]:
32
+ """Load an agent YAML for a specific persona ID. Returns parsed dict or None."""
33
+ agents_dir = home / "agents"
34
+ if not agents_dir.exists():
35
+ return None
36
+ for f in sorted(agents_dir.glob("*.agent.yaml")):
37
+ try:
38
+ raw = f.read_text(encoding="utf-8")
39
+ agent = yaml.safe_load(raw)
40
+ pid = (agent.get("metadata") or {}).get("persona_id")
41
+ if pid == persona_id:
42
+ return dict(agent)
43
+ except (yaml.YAMLError, OSError, AttributeError):
44
+ continue
45
+ return None
46
+
47
+
48
+ def load_persona_from_agent(home: Path, persona_id: str) -> Optional[dict]:
49
+ """Load an agent YAML and extract persona-compatible data.
50
+
51
+ Returns a dict with id, source, model, and system_prompt fields,
52
+ suitable for use by read_persona() and review generation.
53
+ """
54
+ agent = load_agent_yaml(home, persona_id)
55
+ if not agent:
56
+ return None
57
+ return {
58
+ "id": persona_id,
59
+ "source": "agent_yaml",
60
+ "model": agent.get("model"),
61
+ "system_prompt": agent.get("system"),
62
+ "tools": agent.get("tools", []),
63
+ "metadata": agent.get("metadata", {}),
64
+ }