talocode-screenlane 0.1.0__tar.gz

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,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: talocode-screenlane
3
+ Version: 0.1.0
4
+ Summary: Python SDK and CLI for ScreenLane — screen-aware voice command layer for AI agents
5
+ Author: Talocode
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/talocode/screenlane
8
+ Project-URL: Repository, https://github.com/talocode/screenlane
9
+ Keywords: screenlane,talocode,ai-agents,mcp,voice,screen-aware
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == "dev"
17
+ Requires-Dist: build; extra == "dev"
18
+ Requires-Dist: twine; extra == "dev"
19
+
20
+ # talocode-screenlane (Python)
21
+
22
+ Python SDK and lightweight CLI for [ScreenLane](https://github.com/talocode/screenlane).
23
+
24
+ The Node package owns OS capture, MCP, and the local API. This package is:
25
+
26
+ - An HTTP client for `screenlane serve` (default `http://127.0.0.1:3070`)
27
+ - Offline deterministic command helpers
28
+ - CLI: `screenlane-py`
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install talocode-screenlane
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```python
39
+ from talocode_screenlane import ScreenLaneClient
40
+
41
+ client = ScreenLaneClient(base_url="http://127.0.0.1:3070")
42
+ # If SCREENLANE_REQUIRE_AUTH=true on the server:
43
+ # client = ScreenLaneClient(api_key=os.environ["TALOCODE_API_KEY"])
44
+
45
+ print(client.health())
46
+ print(client.command({
47
+ "text": "Fix this error",
48
+ "contextText": "TypeError: ...",
49
+ "target": "codra",
50
+ }))
51
+ ```
52
+
53
+ CLI:
54
+
55
+ ```bash
56
+ screenlane-py health
57
+ screenlane-py command --text "Fix this error" --context-file error.txt
58
+ screenlane-py command --text "Fix this error" --context-text "..." --offline
59
+ screenlane-py demo
60
+ ```
61
+
62
+ Auth uses **only** `TALOCODE_API_KEY` (Bearer header).
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,47 @@
1
+ # talocode-screenlane (Python)
2
+
3
+ Python SDK and lightweight CLI for [ScreenLane](https://github.com/talocode/screenlane).
4
+
5
+ The Node package owns OS capture, MCP, and the local API. This package is:
6
+
7
+ - An HTTP client for `screenlane serve` (default `http://127.0.0.1:3070`)
8
+ - Offline deterministic command helpers
9
+ - CLI: `screenlane-py`
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install talocode-screenlane
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```python
20
+ from talocode_screenlane import ScreenLaneClient
21
+
22
+ client = ScreenLaneClient(base_url="http://127.0.0.1:3070")
23
+ # If SCREENLANE_REQUIRE_AUTH=true on the server:
24
+ # client = ScreenLaneClient(api_key=os.environ["TALOCODE_API_KEY"])
25
+
26
+ print(client.health())
27
+ print(client.command({
28
+ "text": "Fix this error",
29
+ "contextText": "TypeError: ...",
30
+ "target": "codra",
31
+ }))
32
+ ```
33
+
34
+ CLI:
35
+
36
+ ```bash
37
+ screenlane-py health
38
+ screenlane-py command --text "Fix this error" --context-file error.txt
39
+ screenlane-py command --text "Fix this error" --context-text "..." --offline
40
+ screenlane-py demo
41
+ ```
42
+
43
+ Auth uses **only** `TALOCODE_API_KEY` (Bearer header).
44
+
45
+ ## License
46
+
47
+ MIT
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "talocode-screenlane"
7
+ version = "0.1.0"
8
+ description = "Python SDK and CLI for ScreenLane — screen-aware voice command layer for AI agents"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Talocode" }]
13
+ keywords = ["screenlane", "talocode", "ai-agents", "mcp", "voice", "screen-aware"]
14
+ classifiers = [
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ ]
19
+ dependencies = []
20
+
21
+ [project.optional-dependencies]
22
+ dev = ["pytest>=7.0", "build", "twine"]
23
+
24
+ [project.scripts]
25
+ screenlane-py = "talocode_screenlane.cli:main"
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/talocode/screenlane"
29
+ Repository = "https://github.com/talocode/screenlane"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["."]
33
+ include = ["talocode_screenlane*"]
34
+
35
+ [tool.pytest.ini_options]
36
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """talocode-screenlane — Python client for ScreenLane."""
2
+
3
+ from .client import ScreenLaneClient
4
+
5
+ __version__ = "0.1.0"
6
+ __all__ = ["ScreenLaneClient", "__version__"]
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from . import __version__
9
+ from .client import ScreenLaneClient, ScreenLaneError, build_local_command
10
+
11
+
12
+ def _print(data: object) -> None:
13
+ if isinstance(data, str):
14
+ print(data)
15
+ else:
16
+ print(json.dumps(data, indent=2))
17
+
18
+
19
+ def main(argv: list[str] | None = None) -> int:
20
+ parser = argparse.ArgumentParser(
21
+ prog="screenlane-py",
22
+ description="Python CLI for ScreenLane (HTTP client + offline helpers)",
23
+ )
24
+ parser.add_argument("--base-url", default="http://127.0.0.1:3070")
25
+ parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
26
+ sub = parser.add_subparsers(dest="cmd", required=True)
27
+
28
+ sub.add_parser("health", help="GET /v1/screenlane/health")
29
+ sub.add_parser("doctor", help="GET /v1/screenlane/doctor")
30
+ sub.add_parser("demo", help="POST /v1/screenlane/demo (or offline fallback)")
31
+
32
+ p_cmd = sub.add_parser("command", help="Build agent command via API or offline")
33
+ p_cmd.add_argument("--text", required=True)
34
+ p_cmd.add_argument("--context-file")
35
+ p_cmd.add_argument("--context-text", default="")
36
+ p_cmd.add_argument("--target", default="stdout")
37
+ p_cmd.add_argument("--offline", action="store_true", help="Do not call server")
38
+
39
+ p_cap = sub.add_parser("capture", help="POST capture")
40
+ p_cap.add_argument("--text")
41
+ p_cap.add_argument("--source", default="text")
42
+
43
+ args = parser.parse_args(argv)
44
+ client = ScreenLaneClient(base_url=args.base_url)
45
+
46
+ try:
47
+ if args.cmd == "health":
48
+ _print(client.health())
49
+ return 0
50
+ if args.cmd == "doctor":
51
+ _print(client.doctor())
52
+ return 0
53
+ if args.cmd == "demo":
54
+ try:
55
+ _print(client.demo())
56
+ except ScreenLaneError:
57
+ # offline deterministic demo
58
+ _print(
59
+ build_local_command(
60
+ "Fix this error",
61
+ "TypeError: cannot read map of undefined at Dashboard.tsx:42",
62
+ target="codra",
63
+ )
64
+ )
65
+ return 0
66
+ if args.cmd == "command":
67
+ ctx = args.context_text or ""
68
+ if args.context_file:
69
+ ctx = Path(args.context_file).read_text(encoding="utf-8")
70
+ if args.offline:
71
+ _print(build_local_command(args.text, ctx, args.target))
72
+ return 0
73
+ try:
74
+ _print(
75
+ client.command(
76
+ {
77
+ "text": args.text,
78
+ "contextText": ctx,
79
+ "target": args.target,
80
+ "save": False,
81
+ }
82
+ )
83
+ )
84
+ except ScreenLaneError:
85
+ _print(build_local_command(args.text, ctx, args.target))
86
+ return 0
87
+ if args.cmd == "capture":
88
+ _print(client.capture({"source": args.source, "text": args.text, "save": False}))
89
+ return 0
90
+ except ScreenLaneError as e:
91
+ print(f"Error: {e}", file=sys.stderr)
92
+ return 1
93
+ return 1
94
+
95
+
96
+ if __name__ == "__main__":
97
+ raise SystemExit(main())
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import urllib.error
6
+ import urllib.request
7
+ from typing import Any, Optional
8
+
9
+
10
+ class ScreenLaneError(Exception):
11
+ def __init__(self, message: str, status: Optional[int] = None):
12
+ super().__init__(message)
13
+ self.status = status
14
+
15
+
16
+ class ScreenLaneClient:
17
+ """HTTP client for a local ScreenLane server + local helpers."""
18
+
19
+ def __init__(
20
+ self,
21
+ base_url: str = "http://127.0.0.1:3070",
22
+ api_key: Optional[str] = None,
23
+ timeout: float = 30.0,
24
+ ) -> None:
25
+ self.base_url = base_url.rstrip("/")
26
+ self.api_key = api_key or os.environ.get("TALOCODE_API_KEY")
27
+ self.timeout = timeout
28
+
29
+ def _request(self, method: str, path: str, body: Any = None) -> Any:
30
+ url = f"{self.base_url}{path}"
31
+ data = None if body is None else json.dumps(body).encode("utf-8")
32
+ headers = {"Accept": "application/json", "Content-Type": "application/json"}
33
+ if self.api_key:
34
+ headers["Authorization"] = f"Bearer {self.api_key}"
35
+ headers["X-Talocode-Api-Key"] = self.api_key
36
+ req = urllib.request.Request(url, data=data, headers=headers, method=method)
37
+ try:
38
+ with urllib.request.urlopen(req, timeout=self.timeout) as resp:
39
+ raw = resp.read().decode("utf-8")
40
+ return json.loads(raw) if raw else {}
41
+ except urllib.error.HTTPError as e:
42
+ detail = e.read().decode("utf-8", errors="replace")
43
+ raise ScreenLaneError(f"HTTP {e.code}: {detail[:300]}", status=e.code) from e
44
+ except urllib.error.URLError as e:
45
+ raise ScreenLaneError(
46
+ f"Cannot reach ScreenLane at {self.base_url}: {e.reason}. "
47
+ "Start the server with `screenlane serve`."
48
+ ) from e
49
+
50
+ def health(self) -> Any:
51
+ return self._request("GET", "/v1/screenlane/health")
52
+
53
+ def doctor(self) -> Any:
54
+ return self._request("GET", "/v1/screenlane/doctor")
55
+
56
+ def capture(self, payload: Optional[dict] = None) -> Any:
57
+ return self._request("POST", "/v1/screenlane/capture", payload or {})
58
+
59
+ def dictate(self, payload: Optional[dict] = None) -> Any:
60
+ return self._request("POST", "/v1/screenlane/dictate", payload or {})
61
+
62
+ def command(self, payload: Optional[dict] = None) -> Any:
63
+ return self._request("POST", "/v1/screenlane/command", payload or {})
64
+
65
+ def send(self, payload: Optional[dict] = None) -> Any:
66
+ return self._request("POST", "/v1/screenlane/send", payload or {})
67
+
68
+ def list_contexts(self) -> Any:
69
+ return self._request("GET", "/v1/screenlane/contexts")
70
+
71
+ def list_commands(self) -> Any:
72
+ return self._request("GET", "/v1/screenlane/commands")
73
+
74
+ def demo(self) -> Any:
75
+ return self._request("POST", "/v1/screenlane/demo", {})
76
+
77
+
78
+ def build_local_command(
79
+ instruction: str,
80
+ context_text: str = "",
81
+ target: str = "stdout",
82
+ ) -> dict:
83
+ """Deterministic offline helper (no server required)."""
84
+ intent = "general_action"
85
+ lower = f"{instruction}\n{context_text}".lower()
86
+ if any(k in lower for k in ("fix", "error", "debug", "exception")):
87
+ intent = "debug_error"
88
+ elif any(k in lower for k in ("explain", "summarize")):
89
+ intent = "explain"
90
+ elif "reply" in lower or "email" in lower:
91
+ intent = "write_reply"
92
+ prompt = (
93
+ f"Target: {target}\nIntent: {intent}\n\n"
94
+ f"Screen context:\n```\n{context_text[:4000]}\n```\n\n"
95
+ f"User instruction:\n{instruction}\n\n"
96
+ "Act on the instruction using the context. Prefer minimal, safe changes."
97
+ )
98
+ return {
99
+ "intent": intent,
100
+ "instruction": instruction,
101
+ "target": target,
102
+ "prompt": prompt,
103
+ "offline": True,
104
+ }
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: talocode-screenlane
3
+ Version: 0.1.0
4
+ Summary: Python SDK and CLI for ScreenLane — screen-aware voice command layer for AI agents
5
+ Author: Talocode
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/talocode/screenlane
8
+ Project-URL: Repository, https://github.com/talocode/screenlane
9
+ Keywords: screenlane,talocode,ai-agents,mcp,voice,screen-aware
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == "dev"
17
+ Requires-Dist: build; extra == "dev"
18
+ Requires-Dist: twine; extra == "dev"
19
+
20
+ # talocode-screenlane (Python)
21
+
22
+ Python SDK and lightweight CLI for [ScreenLane](https://github.com/talocode/screenlane).
23
+
24
+ The Node package owns OS capture, MCP, and the local API. This package is:
25
+
26
+ - An HTTP client for `screenlane serve` (default `http://127.0.0.1:3070`)
27
+ - Offline deterministic command helpers
28
+ - CLI: `screenlane-py`
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install talocode-screenlane
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```python
39
+ from talocode_screenlane import ScreenLaneClient
40
+
41
+ client = ScreenLaneClient(base_url="http://127.0.0.1:3070")
42
+ # If SCREENLANE_REQUIRE_AUTH=true on the server:
43
+ # client = ScreenLaneClient(api_key=os.environ["TALOCODE_API_KEY"])
44
+
45
+ print(client.health())
46
+ print(client.command({
47
+ "text": "Fix this error",
48
+ "contextText": "TypeError: ...",
49
+ "target": "codra",
50
+ }))
51
+ ```
52
+
53
+ CLI:
54
+
55
+ ```bash
56
+ screenlane-py health
57
+ screenlane-py command --text "Fix this error" --context-file error.txt
58
+ screenlane-py command --text "Fix this error" --context-text "..." --offline
59
+ screenlane-py demo
60
+ ```
61
+
62
+ Auth uses **only** `TALOCODE_API_KEY` (Bearer header).
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ talocode_screenlane/__init__.py
4
+ talocode_screenlane/cli.py
5
+ talocode_screenlane/client.py
6
+ talocode_screenlane.egg-info/PKG-INFO
7
+ talocode_screenlane.egg-info/SOURCES.txt
8
+ talocode_screenlane.egg-info/dependency_links.txt
9
+ talocode_screenlane.egg-info/entry_points.txt
10
+ talocode_screenlane.egg-info/requires.txt
11
+ talocode_screenlane.egg-info/top_level.txt
12
+ tests/test_client.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ screenlane-py = talocode_screenlane.cli:main
@@ -0,0 +1,5 @@
1
+
2
+ [dev]
3
+ pytest>=7.0
4
+ build
5
+ twine
@@ -0,0 +1 @@
1
+ talocode_screenlane
@@ -0,0 +1,22 @@
1
+ from talocode_screenlane.client import build_local_command
2
+ from talocode_screenlane import __version__
3
+
4
+
5
+ def test_version():
6
+ assert __version__ == "0.1.0"
7
+
8
+
9
+ def test_build_local_command_debug():
10
+ cmd = build_local_command(
11
+ "Fix this error",
12
+ "TypeError: boom at app.ts:1",
13
+ target="codra",
14
+ )
15
+ assert cmd["intent"] == "debug_error"
16
+ assert "Fix this error" in cmd["prompt"]
17
+ assert cmd["offline"] is True
18
+
19
+
20
+ def test_build_local_command_explain():
21
+ cmd = build_local_command("Explain this page", "Hello docs", target="stdout")
22
+ assert cmd["intent"] == "explain"