sfhtml 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.
sfhtml-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: sfhtml
3
+ Version: 0.1.0
4
+ Summary: Single-File HTML AI-Skill CLI — Python wrapper
5
+ Author-email: anyrust <ggen652@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/anyrust/sfhtml
8
+ Project-URL: Repository, https://github.com/anyrust/sfhtml
9
+ Keywords: html,single-file,ai,cli,editor
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: Topic :: Text Processing :: Markup :: HTML
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+
19
+ # sfhtml (Python)
20
+
21
+ Python wrapper for [sfhtml](https://github.com/anyrust/sfhtml) — Single-File HTML AI-Skill CLI.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install sfhtml
27
+ ```
28
+
29
+ > **Requires** the `sfhtml` binary. Install via `cargo install sfhtml` or download from [GitHub Releases](https://github.com/anyrust/sfhtml/releases).
30
+
31
+ ## Usage
32
+
33
+ ### As a Python library
34
+
35
+ ```python
36
+ import sfhtml
37
+
38
+ # Scan for HTML files
39
+ files = sfhtml.scan("./my-project")
40
+
41
+ # Read file header
42
+ header = sfhtml.header("app.html")
43
+
44
+ # Apply a diff
45
+ result = sfhtml.apply("app.html", "patch.diff", backup=True)
46
+
47
+ # Validate
48
+ report = sfhtml.validate("app.html")
49
+
50
+ # Browser interaction
51
+ sfhtml.debug_start("app.html")
52
+ sfhtml.page_click("#submit-btn")
53
+ logs = sfhtml.page_console()
54
+ sfhtml.debug_stop()
55
+
56
+ # Run any sfhtml command
57
+ result = sfhtml.run("anchor-list", "app.html")
58
+ ```
59
+
60
+ ### As a CLI (same as the Rust binary)
61
+
62
+ ```bash
63
+ sfhtml scan . --recursive --json
64
+ sfhtml header app.html
65
+ sfhtml page screenshot --output shot.png
66
+ ```
67
+
68
+ ## License
69
+
70
+ MIT
sfhtml-0.1.0/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # sfhtml (Python)
2
+
3
+ Python wrapper for [sfhtml](https://github.com/anyrust/sfhtml) — Single-File HTML AI-Skill CLI.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install sfhtml
9
+ ```
10
+
11
+ > **Requires** the `sfhtml` binary. Install via `cargo install sfhtml` or download from [GitHub Releases](https://github.com/anyrust/sfhtml/releases).
12
+
13
+ ## Usage
14
+
15
+ ### As a Python library
16
+
17
+ ```python
18
+ import sfhtml
19
+
20
+ # Scan for HTML files
21
+ files = sfhtml.scan("./my-project")
22
+
23
+ # Read file header
24
+ header = sfhtml.header("app.html")
25
+
26
+ # Apply a diff
27
+ result = sfhtml.apply("app.html", "patch.diff", backup=True)
28
+
29
+ # Validate
30
+ report = sfhtml.validate("app.html")
31
+
32
+ # Browser interaction
33
+ sfhtml.debug_start("app.html")
34
+ sfhtml.page_click("#submit-btn")
35
+ logs = sfhtml.page_console()
36
+ sfhtml.debug_stop()
37
+
38
+ # Run any sfhtml command
39
+ result = sfhtml.run("anchor-list", "app.html")
40
+ ```
41
+
42
+ ### As a CLI (same as the Rust binary)
43
+
44
+ ```bash
45
+ sfhtml scan . --recursive --json
46
+ sfhtml header app.html
47
+ sfhtml page screenshot --output shot.png
48
+ ```
49
+
50
+ ## License
51
+
52
+ MIT
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sfhtml"
7
+ version = "0.1.0"
8
+ description = "Single-File HTML AI-Skill CLI — Python wrapper"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.8"
12
+ authors = [{name = "anyrust", email = "ggen652@gmail.com"}]
13
+ keywords = ["html", "single-file", "ai", "cli", "editor"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Software Development :: Build Tools",
20
+ "Topic :: Text Processing :: Markup :: HTML",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/anyrust/sfhtml"
25
+ Repository = "https://github.com/anyrust/sfhtml"
26
+
27
+ [project.scripts]
28
+ sfhtml = "sfhtml.cli:main"
sfhtml-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,200 @@
1
+ """sfhtml — Single-File HTML AI-Skill CLI (Python wrapper)
2
+
3
+ Provides a Python interface to the sfhtml Rust binary.
4
+ All commands support --json for structured output.
5
+
6
+ Usage:
7
+ import sfhtml
8
+ result = sfhtml.run("scan", ".", "--recursive")
9
+ result = sfhtml.scan(".")
10
+ result = sfhtml.header("app.html")
11
+ """
12
+
13
+ import json
14
+ import subprocess
15
+ import shutil
16
+ import sys
17
+ from pathlib import Path
18
+ from typing import Any, Dict, List, Optional, Union
19
+
20
+
21
+ def _find_binary() -> str:
22
+ """Find the sfhtml binary. Checks: same directory, PATH, cargo install location."""
23
+ # 1. Bundled binary next to this package
24
+ pkg_dir = Path(__file__).parent
25
+ for candidate in [pkg_dir / "sfhtml", pkg_dir / "sfhtml.exe"]:
26
+ if candidate.exists():
27
+ return str(candidate)
28
+
29
+ # 2. On PATH
30
+ found = shutil.which("sfhtml")
31
+ if found:
32
+ return found
33
+
34
+ # 3. Cargo install location
35
+ cargo_bin = Path.home() / ".cargo" / "bin" / "sfhtml"
36
+ if cargo_bin.exists():
37
+ return str(cargo_bin)
38
+
39
+ raise FileNotFoundError(
40
+ "sfhtml binary not found. Install it with:\n"
41
+ " cargo install sfhtml\n"
42
+ "Or download from: https://github.com/anyrust/sfhtml/releases"
43
+ )
44
+
45
+
46
+ def run(*args: str, json_output: bool = True, timeout: Optional[int] = None) -> Union[Dict, str]:
47
+ """Run an sfhtml command and return the result.
48
+
49
+ Args:
50
+ *args: Command arguments (e.g. "scan", ".", "--recursive")
51
+ json_output: If True, append --json and parse output as JSON
52
+ timeout: Timeout in seconds (None = no timeout)
53
+
54
+ Returns:
55
+ Parsed JSON dict if json_output=True, raw stdout string otherwise.
56
+
57
+ Raises:
58
+ FileNotFoundError: If sfhtml binary is not found
59
+ subprocess.CalledProcessError: If command fails
60
+ json.JSONDecodeError: If JSON parsing fails
61
+ """
62
+ binary = _find_binary()
63
+ cmd = [binary] + list(args)
64
+ if json_output and "--json" not in args:
65
+ cmd.append("--json")
66
+
67
+ result = subprocess.run(
68
+ cmd,
69
+ capture_output=True,
70
+ text=True,
71
+ timeout=timeout,
72
+ )
73
+
74
+ if result.returncode != 0:
75
+ raise subprocess.CalledProcessError(
76
+ result.returncode, cmd, result.stdout, result.stderr
77
+ )
78
+
79
+ if json_output:
80
+ return json.loads(result.stdout)
81
+ return result.stdout
82
+
83
+
84
+ # ---------------------------------------------------------------------------
85
+ # Convenience functions
86
+ # ---------------------------------------------------------------------------
87
+
88
+ def scan(directory: str = ".", recursive: bool = True, **kwargs) -> Dict:
89
+ """Scan a directory for HTML files with AI-SKILL-HEADERs."""
90
+ args = ["scan", directory]
91
+ if recursive:
92
+ args.append("--recursive")
93
+ for k, v in kwargs.items():
94
+ args.extend([f"--{k.replace('_', '-')}", str(v)])
95
+ return run(*args)
96
+
97
+
98
+ def header(file: str, section: Optional[int] = None) -> Dict:
99
+ """Extract the AI-SKILL-HEADER from an HTML file."""
100
+ args = ["header", file]
101
+ if section is not None:
102
+ args.extend(["--section", str(section)])
103
+ return run(*args)
104
+
105
+
106
+ def read(file: str, start: Optional[int] = None, end: Optional[int] = None,
107
+ head: Optional[int] = None, tail: Optional[int] = None) -> str:
108
+ """Read lines from a file."""
109
+ args = ["read", file]
110
+ if start is not None:
111
+ args.append(str(start))
112
+ if end is not None:
113
+ args.append(str(end))
114
+ if head is not None:
115
+ args.extend(["--head", str(head)])
116
+ if tail is not None:
117
+ args.extend(["--tail", str(tail)])
118
+ return run(*args, json_output=False)
119
+
120
+
121
+ def locate(file: str, anchor: str, context: int = 0) -> Dict:
122
+ """Locate a code anchor in the file."""
123
+ args = ["locate", file, anchor, "--context", str(context)]
124
+ return run(*args)
125
+
126
+
127
+ def apply(file: str, diff: str, dry_run: bool = False, backup: bool = False) -> Dict:
128
+ """Apply a unified diff to a file."""
129
+ args = ["apply", file, "--diff", diff]
130
+ if dry_run:
131
+ args.append("--dry-run")
132
+ if backup:
133
+ args.append("--backup")
134
+ return run(*args)
135
+
136
+
137
+ def validate(file: str, fix: bool = False) -> Dict:
138
+ """Validate header-to-code consistency."""
139
+ args = ["validate", file]
140
+ if fix:
141
+ args.append("--fix")
142
+ return run(*args)
143
+
144
+
145
+ def module(file: str, depth: int = 0) -> Dict:
146
+ """Scan local ES module / resource dependencies."""
147
+ args = ["module", file, "--depth", str(depth)]
148
+ return run(*args)
149
+
150
+
151
+ def search(query: str, directory: str = ".", top: int = 5) -> Dict:
152
+ """Search HTML files by query."""
153
+ return run("search", query, "--dir", directory, "--top", str(top))
154
+
155
+
156
+ def page_screenshot(port: int = 9222, selector: Optional[str] = None,
157
+ output: Optional[str] = None) -> Dict:
158
+ """Capture a page screenshot."""
159
+ args = ["page", "screenshot", "--port", str(port)]
160
+ if selector:
161
+ args.extend(["--selector", selector])
162
+ if output:
163
+ args.extend(["--output", output])
164
+ return run(*args)
165
+
166
+
167
+ def page_click(selector: str, port: int = 9222) -> Dict:
168
+ """Click an element on the page."""
169
+ return run("page", "click", selector, "--port", str(port))
170
+
171
+
172
+ def page_eval(expression: str, port: int = 9222) -> Dict:
173
+ """Evaluate JavaScript in the page."""
174
+ return run("page", "eval", expression, "--port", str(port))
175
+
176
+
177
+ def page_dom(port: int = 9222, selector: Optional[str] = None) -> Dict:
178
+ """Get page DOM HTML."""
179
+ args = ["page", "dom", "--port", str(port)]
180
+ if selector:
181
+ args.extend(["--selector", selector])
182
+ return run(*args)
183
+
184
+
185
+ def page_console(port: int = 9222) -> Dict:
186
+ """Get console log messages."""
187
+ return run("page", "console", "--port", str(port))
188
+
189
+
190
+ def debug_start(file: str, port: int = 9222, headless: bool = True) -> Dict:
191
+ """Start a browser with CDP debugging."""
192
+ args = ["debug", "start", file, "--port", str(port)]
193
+ if not headless:
194
+ args.append("--no-headless")
195
+ return run(*args)
196
+
197
+
198
+ def debug_stop(port: int = 9222) -> Dict:
199
+ """Stop a browser session."""
200
+ return run("debug", "stop", "--port", str(port))
@@ -0,0 +1,37 @@
1
+ """CLI entry point — delegates to the sfhtml Rust binary."""
2
+
3
+ import sys
4
+ import os
5
+ import shutil
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+
10
+ def _find_binary() -> str:
11
+ pkg_dir = Path(__file__).parent
12
+ for candidate in [pkg_dir / "sfhtml", pkg_dir / "sfhtml.exe"]:
13
+ if candidate.exists():
14
+ return str(candidate)
15
+ found = shutil.which("sfhtml")
16
+ if found:
17
+ return found
18
+ cargo_bin = Path.home() / ".cargo" / "bin" / "sfhtml"
19
+ if cargo_bin.exists():
20
+ return str(cargo_bin)
21
+ print(
22
+ "Error: sfhtml binary not found.\n"
23
+ "Install with: cargo install sfhtml\n"
24
+ "Or download from: https://github.com/anyrust/sfhtml/releases",
25
+ file=sys.stderr,
26
+ )
27
+ sys.exit(1)
28
+
29
+
30
+ def main():
31
+ binary = _find_binary()
32
+ result = subprocess.run([binary] + sys.argv[1:])
33
+ sys.exit(result.returncode)
34
+
35
+
36
+ if __name__ == "__main__":
37
+ main()
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: sfhtml
3
+ Version: 0.1.0
4
+ Summary: Single-File HTML AI-Skill CLI — Python wrapper
5
+ Author-email: anyrust <ggen652@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/anyrust/sfhtml
8
+ Project-URL: Repository, https://github.com/anyrust/sfhtml
9
+ Keywords: html,single-file,ai,cli,editor
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: Topic :: Text Processing :: Markup :: HTML
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+
19
+ # sfhtml (Python)
20
+
21
+ Python wrapper for [sfhtml](https://github.com/anyrust/sfhtml) — Single-File HTML AI-Skill CLI.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install sfhtml
27
+ ```
28
+
29
+ > **Requires** the `sfhtml` binary. Install via `cargo install sfhtml` or download from [GitHub Releases](https://github.com/anyrust/sfhtml/releases).
30
+
31
+ ## Usage
32
+
33
+ ### As a Python library
34
+
35
+ ```python
36
+ import sfhtml
37
+
38
+ # Scan for HTML files
39
+ files = sfhtml.scan("./my-project")
40
+
41
+ # Read file header
42
+ header = sfhtml.header("app.html")
43
+
44
+ # Apply a diff
45
+ result = sfhtml.apply("app.html", "patch.diff", backup=True)
46
+
47
+ # Validate
48
+ report = sfhtml.validate("app.html")
49
+
50
+ # Browser interaction
51
+ sfhtml.debug_start("app.html")
52
+ sfhtml.page_click("#submit-btn")
53
+ logs = sfhtml.page_console()
54
+ sfhtml.debug_stop()
55
+
56
+ # Run any sfhtml command
57
+ result = sfhtml.run("anchor-list", "app.html")
58
+ ```
59
+
60
+ ### As a CLI (same as the Rust binary)
61
+
62
+ ```bash
63
+ sfhtml scan . --recursive --json
64
+ sfhtml header app.html
65
+ sfhtml page screenshot --output shot.png
66
+ ```
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ sfhtml/__init__.py
4
+ sfhtml/cli.py
5
+ sfhtml.egg-info/PKG-INFO
6
+ sfhtml.egg-info/SOURCES.txt
7
+ sfhtml.egg-info/dependency_links.txt
8
+ sfhtml.egg-info/entry_points.txt
9
+ sfhtml.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sfhtml = sfhtml.cli:main
@@ -0,0 +1 @@
1
+ sfhtml