hermes-font-scale 0.1.1__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.
- hermes_font_scale-0.1.1/LICENSE +21 -0
- hermes_font_scale-0.1.1/PKG-INFO +147 -0
- hermes_font_scale-0.1.1/README.md +121 -0
- hermes_font_scale-0.1.1/pyproject.toml +55 -0
- hermes_font_scale-0.1.1/setup.cfg +4 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/__init__.py +12 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/__main__.py +8 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/cli.py +190 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/constants.py +99 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/doctor.py +136 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/locate.py +140 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/py.typed +0 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale/scale.py +223 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale.egg-info/PKG-INFO +147 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale.egg-info/SOURCES.txt +21 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale.egg-info/dependency_links.txt +1 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale.egg-info/entry_points.txt +2 -0
- hermes_font_scale-0.1.1/src/hermes_font_scale.egg-info/top_level.txt +1 -0
- hermes_font_scale-0.1.1/tests/test_cli.py +155 -0
- hermes_font_scale-0.1.1/tests/test_cli_inproc.py +116 -0
- hermes_font_scale-0.1.1/tests/test_doctor.py +91 -0
- hermes_font_scale-0.1.1/tests/test_locate.py +61 -0
- hermes_font_scale-0.1.1/tests/test_scale.py +146 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LUKE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-font-scale
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Unofficial community helper — make Hermes Desktop GUI font bigger in one command.
|
|
5
|
+
Author: LUKE
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hsukevin0407-crypto/hermes-font-scale
|
|
8
|
+
Project-URL: Issues, https://github.com/hsukevin0407-crypto/hermes-font-scale/issues
|
|
9
|
+
Keywords: hermes-agent,cli,accessibility,font-size,electron
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# 🐍 hermes-font-scale
|
|
28
|
+
|
|
29
|
+
> Unofficial community helper — patch **Hermes Desktop GUI** font size in one command, atomically and reversibly.
|
|
30
|
+
> NOT affiliated with [NousResearch/hermes-agent](https://github.com/NousResearch/hermes-agent).
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ✨ Features
|
|
40
|
+
|
|
41
|
+
- **Atomic font patch** — rewrites only the `html { font-size: clamp(...) }` line; crash-safe via temp-file + `os.replace()`
|
|
42
|
+
- **Reversible** — `reset` restores from an auto-created `.bak`; `set` is idempotent and skips unnecessary writes
|
|
43
|
+
- **Zero runtime deps** — stdlib only; works on Python 3.9–3.12 across Windows / macOS / Linux
|
|
44
|
+
- **Multi-OS path resolution** — auto-detects Hermes install from `HERMES_HOME`, env var, or 10+ known install paths
|
|
45
|
+
- **Diagnostic `doctor` command** — 4-check health report pinpoints the exact failure before you patch
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🚀 Getting Started
|
|
50
|
+
|
|
51
|
+
### Prerequisites
|
|
52
|
+
|
|
53
|
+
- Python >= 3.9
|
|
54
|
+
|
|
55
|
+
### Installation
|
|
56
|
+
|
|
57
|
+
Currently available from source only (PyPI publication pending):
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install "git+https://github.com/hsukevin0407-crypto/hermes-font-scale.git@v0.1.1"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or clone and install locally:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/hsukevin0407-crypto/hermes-font-scale.git
|
|
67
|
+
cd hermes-font-scale
|
|
68
|
+
pip install -e .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Usage
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Check current state (run this first)
|
|
75
|
+
hermes-font-scale status
|
|
76
|
+
|
|
77
|
+
# Set base font size (10–32 px; responsive max is auto-computed)
|
|
78
|
+
hermes-font-scale set 18
|
|
79
|
+
|
|
80
|
+
# Preview without writing anything
|
|
81
|
+
hermes-font-scale set 18 --dry-run
|
|
82
|
+
|
|
83
|
+
# Run the 4-check diagnostic
|
|
84
|
+
hermes-font-scale doctor
|
|
85
|
+
|
|
86
|
+
# Restore the original CSS from the .bak file
|
|
87
|
+
hermes-font-scale reset
|
|
88
|
+
|
|
89
|
+
# Machine-readable output
|
|
90
|
+
hermes-font-scale status --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
After `set`, **restart Hermes Desktop** to see the change.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🏗️ Architecture
|
|
98
|
+
|
|
99
|
+
```mermaid
|
|
100
|
+
graph LR
|
|
101
|
+
A[CLI: hermes-font-scale] --> B{Command}
|
|
102
|
+
B -->|set N| C[Locate globals.css]
|
|
103
|
+
B -->|reset| D[Restore from .bak]
|
|
104
|
+
B -->|status| E[Read current value]
|
|
105
|
+
B -->|doctor| F[4-check diagnostic]
|
|
106
|
+
C --> G[Atomic rewrite via os.replace]
|
|
107
|
+
G --> H[globals.css patched]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Hermes Desktop hard-codes font size in one CSS anchor:
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
/* node_modules/@nous-research/ui/dist/ui/globals.css */
|
|
114
|
+
html {
|
|
115
|
+
font-size: clamp(14px, calc(14px + 2 * ((100vw - 1400px) / 400)), 18px);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`hermes-font-scale set N` rewrites the two numeric bounds to `N` and `N+4`, preserving responsive behavior. Everything else in the file is untouched.
|
|
120
|
+
|
|
121
|
+
**Compatibility note:** the official Hermes Desktop installer may bundle `node_modules` inside `app.asar`. Run `hermes-font-scale doctor` — if the "font-size clause present" check fails because the file is inside an ASAR archive, see the [open issue](https://github.com/hsukevin0407-crypto/hermes-font-scale/issues) for workarounds.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 🤝 Contributing
|
|
126
|
+
|
|
127
|
+
Pull requests are welcome. For major changes, please open an issue first.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Run tests
|
|
131
|
+
pip install pytest pytest-cov
|
|
132
|
+
pytest
|
|
133
|
+
|
|
134
|
+
# Lint
|
|
135
|
+
pip install ruff
|
|
136
|
+
ruff check src tests
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
CI runs on Python 3.9, 3.10, 3.11, 3.12 across Ubuntu / Windows / macOS.
|
|
140
|
+
|
|
141
|
+
## 📄 License
|
|
142
|
+
|
|
143
|
+
[MIT](LICENSE)
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
> **Disclaimer:** Unofficial community project. Not affiliated with or endorsed by Nous Research. Use at your own risk.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# 🐍 hermes-font-scale
|
|
2
|
+
|
|
3
|
+
> Unofficial community helper — patch **Hermes Desktop GUI** font size in one command, atomically and reversibly.
|
|
4
|
+
> NOT affiliated with [NousResearch/hermes-agent](https://github.com/NousResearch/hermes-agent).
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ✨ Features
|
|
14
|
+
|
|
15
|
+
- **Atomic font patch** — rewrites only the `html { font-size: clamp(...) }` line; crash-safe via temp-file + `os.replace()`
|
|
16
|
+
- **Reversible** — `reset` restores from an auto-created `.bak`; `set` is idempotent and skips unnecessary writes
|
|
17
|
+
- **Zero runtime deps** — stdlib only; works on Python 3.9–3.12 across Windows / macOS / Linux
|
|
18
|
+
- **Multi-OS path resolution** — auto-detects Hermes install from `HERMES_HOME`, env var, or 10+ known install paths
|
|
19
|
+
- **Diagnostic `doctor` command** — 4-check health report pinpoints the exact failure before you patch
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🚀 Getting Started
|
|
24
|
+
|
|
25
|
+
### Prerequisites
|
|
26
|
+
|
|
27
|
+
- Python >= 3.9
|
|
28
|
+
|
|
29
|
+
### Installation
|
|
30
|
+
|
|
31
|
+
Currently available from source only (PyPI publication pending):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install "git+https://github.com/hsukevin0407-crypto/hermes-font-scale.git@v0.1.1"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or clone and install locally:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/hsukevin0407-crypto/hermes-font-scale.git
|
|
41
|
+
cd hermes-font-scale
|
|
42
|
+
pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Usage
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Check current state (run this first)
|
|
49
|
+
hermes-font-scale status
|
|
50
|
+
|
|
51
|
+
# Set base font size (10–32 px; responsive max is auto-computed)
|
|
52
|
+
hermes-font-scale set 18
|
|
53
|
+
|
|
54
|
+
# Preview without writing anything
|
|
55
|
+
hermes-font-scale set 18 --dry-run
|
|
56
|
+
|
|
57
|
+
# Run the 4-check diagnostic
|
|
58
|
+
hermes-font-scale doctor
|
|
59
|
+
|
|
60
|
+
# Restore the original CSS from the .bak file
|
|
61
|
+
hermes-font-scale reset
|
|
62
|
+
|
|
63
|
+
# Machine-readable output
|
|
64
|
+
hermes-font-scale status --json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
After `set`, **restart Hermes Desktop** to see the change.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 🏗️ Architecture
|
|
72
|
+
|
|
73
|
+
```mermaid
|
|
74
|
+
graph LR
|
|
75
|
+
A[CLI: hermes-font-scale] --> B{Command}
|
|
76
|
+
B -->|set N| C[Locate globals.css]
|
|
77
|
+
B -->|reset| D[Restore from .bak]
|
|
78
|
+
B -->|status| E[Read current value]
|
|
79
|
+
B -->|doctor| F[4-check diagnostic]
|
|
80
|
+
C --> G[Atomic rewrite via os.replace]
|
|
81
|
+
G --> H[globals.css patched]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Hermes Desktop hard-codes font size in one CSS anchor:
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
/* node_modules/@nous-research/ui/dist/ui/globals.css */
|
|
88
|
+
html {
|
|
89
|
+
font-size: clamp(14px, calc(14px + 2 * ((100vw - 1400px) / 400)), 18px);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`hermes-font-scale set N` rewrites the two numeric bounds to `N` and `N+4`, preserving responsive behavior. Everything else in the file is untouched.
|
|
94
|
+
|
|
95
|
+
**Compatibility note:** the official Hermes Desktop installer may bundle `node_modules` inside `app.asar`. Run `hermes-font-scale doctor` — if the "font-size clause present" check fails because the file is inside an ASAR archive, see the [open issue](https://github.com/hsukevin0407-crypto/hermes-font-scale/issues) for workarounds.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 🤝 Contributing
|
|
100
|
+
|
|
101
|
+
Pull requests are welcome. For major changes, please open an issue first.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Run tests
|
|
105
|
+
pip install pytest pytest-cov
|
|
106
|
+
pytest
|
|
107
|
+
|
|
108
|
+
# Lint
|
|
109
|
+
pip install ruff
|
|
110
|
+
ruff check src tests
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
CI runs on Python 3.9, 3.10, 3.11, 3.12 across Ubuntu / Windows / macOS.
|
|
114
|
+
|
|
115
|
+
## 📄 License
|
|
116
|
+
|
|
117
|
+
[MIT](LICENSE)
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
> **Disclaimer:** Unofficial community project. Not affiliated with or endorsed by Nous Research. Use at your own risk.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hermes-font-scale"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Unofficial community helper — make Hermes Desktop GUI font bigger in one command."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "LUKE" }]
|
|
13
|
+
keywords = ["hermes-agent", "cli", "accessibility", "font-size", "electron"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: End Users/Desktop",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
|
28
|
+
# Intentionally zero runtime deps — stdlib only.
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
hermes-font-scale = "hermes_font_scale.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/hsukevin0407-crypto/hermes-font-scale"
|
|
36
|
+
Issues = "https://github.com/hsukevin0407-crypto/hermes-font-scale/issues"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.package-data]
|
|
42
|
+
hermes_font_scale = ["py.typed"]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
minversion = "7.0"
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
addopts = "-v --tb=short"
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
target-version = "py39"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "W", "I", "B", "UP"]
|
|
55
|
+
ignore = ["E501"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""hermes-font-scale: Unofficial community helper for Hermes Desktop font size.
|
|
2
|
+
|
|
3
|
+
Public API:
|
|
4
|
+
CLI entry point: ``hermes-font-scale`` (see cli.main)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from .constants import VERSION
|
|
10
|
+
|
|
11
|
+
__version__ = VERSION
|
|
12
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Command-line interface for hermes-font-scale.
|
|
2
|
+
|
|
3
|
+
Subcommands:
|
|
4
|
+
set <PX> set font size (10..32)
|
|
5
|
+
reset restore from .bak
|
|
6
|
+
status print current state
|
|
7
|
+
doctor run 4 diagnostic checks
|
|
8
|
+
|
|
9
|
+
Common flags:
|
|
10
|
+
--hermes-home PATH override install root
|
|
11
|
+
--dry-run show what would happen without writing
|
|
12
|
+
--json machine-readable output for status
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# On Windows, the default console codepage is often cp1252 which chokes on
|
|
24
|
+
# the non-ASCII strings we use in messages. Reconfigure stdout/stderr to
|
|
25
|
+
# UTF-8 so help text and error messages don't crash the CLI.
|
|
26
|
+
#
|
|
27
|
+
# Skip this when running under pytest — capsys replaces stdout/stderr
|
|
28
|
+
# and reconfigure() breaks the capture machinery.
|
|
29
|
+
if os.name == "nt" and not os.environ.get("PYTEST_CURRENT_TEST"):
|
|
30
|
+
try:
|
|
31
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[attr-defined]
|
|
32
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace") # type: ignore[attr-defined]
|
|
33
|
+
except (AttributeError, OSError):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
from . import __version__
|
|
37
|
+
from . import doctor as doctor_mod
|
|
38
|
+
from . import scale as scale_mod
|
|
39
|
+
from .constants import MAX_PX, MIN_PX
|
|
40
|
+
from .locate import HermesNotFound, locate_globals_css, _display_path
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
44
|
+
parser = argparse.ArgumentParser(
|
|
45
|
+
prog="hermes-font-scale",
|
|
46
|
+
description=(
|
|
47
|
+
"Unofficial community helper — make Hermes Desktop GUI font "
|
|
48
|
+
"bigger in one command. NOT part of NousResearch/hermes-agent."
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"--version",
|
|
53
|
+
action="version",
|
|
54
|
+
version=f"hermes-font-scale {__version__}",
|
|
55
|
+
)
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"--hermes-home",
|
|
58
|
+
type=Path,
|
|
59
|
+
default=None,
|
|
60
|
+
help="Path to Hermes install root (overrides HERMES_HOME and search).",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
64
|
+
|
|
65
|
+
p_set = sub.add_parser("set", help=f"Set font size in px (range {MIN_PX}..{MAX_PX}).")
|
|
66
|
+
p_set.add_argument("px", type=int, help=f"Target base font size in px ({MIN_PX}..{MAX_PX}).")
|
|
67
|
+
p_set.add_argument(
|
|
68
|
+
"--dry-run",
|
|
69
|
+
action="store_true",
|
|
70
|
+
help="Show diff without writing anything.",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
sub.add_parser("reset", help="Restore globals.css from the .bak file (if any).")
|
|
74
|
+
|
|
75
|
+
p_status = sub.add_parser("status", help="Show current patch state.")
|
|
76
|
+
p_status.add_argument("--json", action="store_true", help="Print JSON instead of text.")
|
|
77
|
+
|
|
78
|
+
sub.add_parser("doctor", help="Run 4 diagnostic checks.")
|
|
79
|
+
|
|
80
|
+
return parser
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _resolve_css(args: argparse.Namespace) -> Path:
|
|
84
|
+
try:
|
|
85
|
+
return locate_globals_css(hermes_home=args.hermes_home)
|
|
86
|
+
except HermesNotFound as exc:
|
|
87
|
+
print(str(exc), file=sys.stderr)
|
|
88
|
+
raise SystemExit(2)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def cmd_set(args: argparse.Namespace) -> int:
|
|
92
|
+
css = _resolve_css(args)
|
|
93
|
+
try:
|
|
94
|
+
if args.dry_run:
|
|
95
|
+
before, after = scale_mod.diff_lines(css, args.px)
|
|
96
|
+
print(f"--- {css}")
|
|
97
|
+
print(f"- {before}")
|
|
98
|
+
print(f"+ {after}")
|
|
99
|
+
print("(dry run — no changes written)")
|
|
100
|
+
return 0
|
|
101
|
+
|
|
102
|
+
result = scale_mod.patch_css(css, args.px, dry_run=False)
|
|
103
|
+
if result.old_base == result.new_base:
|
|
104
|
+
print(f"already at {result.new_base}px — nothing to do")
|
|
105
|
+
return 0
|
|
106
|
+
backup_note = " (backup created)" if result.backup_created else ""
|
|
107
|
+
print(
|
|
108
|
+
f"patched {css.name}: "
|
|
109
|
+
f"{result.old_base}px → {result.new_base}px{backup_note}\n"
|
|
110
|
+
f"restart Hermes Desktop to see the change."
|
|
111
|
+
)
|
|
112
|
+
return 0
|
|
113
|
+
except scale_mod.FontSizeOutOfRange as exc:
|
|
114
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
115
|
+
return 2
|
|
116
|
+
except scale_mod.FontSizeClauseNotFound as exc:
|
|
117
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
118
|
+
return 3
|
|
119
|
+
except PermissionError as exc:
|
|
120
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
121
|
+
return 4
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def cmd_reset(args: argparse.Namespace) -> int:
|
|
125
|
+
css = _resolve_css(args)
|
|
126
|
+
if scale_mod.reset_css(css):
|
|
127
|
+
print(f"restored {css.name} from backup. restart Hermes Desktop.")
|
|
128
|
+
return 0
|
|
129
|
+
print(f"no backup found at {css.name}.bak — nothing to restore.")
|
|
130
|
+
return 1
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def cmd_status(args: argparse.Namespace) -> int:
|
|
134
|
+
try:
|
|
135
|
+
css = locate_globals_css(hermes_home=args.hermes_home)
|
|
136
|
+
except HermesNotFound as exc:
|
|
137
|
+
if args.json:
|
|
138
|
+
print(json.dumps({"ok": False, "error": str(exc)}))
|
|
139
|
+
else:
|
|
140
|
+
print(str(exc), file=sys.stderr)
|
|
141
|
+
return 2
|
|
142
|
+
|
|
143
|
+
base = scale_mod.read_current_base(css)
|
|
144
|
+
backup = css.with_name(css.name + ".bak")
|
|
145
|
+
payload = {
|
|
146
|
+
"ok": True,
|
|
147
|
+
"css_path": _display_path(css),
|
|
148
|
+
"current_base_px": base,
|
|
149
|
+
"backup_exists": backup.exists(),
|
|
150
|
+
}
|
|
151
|
+
if args.json:
|
|
152
|
+
print(json.dumps(payload, indent=2))
|
|
153
|
+
else:
|
|
154
|
+
print(f"css: {payload['css_path']}")
|
|
155
|
+
print(f"current base: {payload['current_base_px']}px")
|
|
156
|
+
print(f"backup: {'yes' if payload['backup_exists'] else 'no'}")
|
|
157
|
+
return 0
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def cmd_doctor(args: argparse.Namespace) -> int:
|
|
161
|
+
css = None
|
|
162
|
+
try:
|
|
163
|
+
css = locate_globals_css(hermes_home=args.hermes_home)
|
|
164
|
+
except HermesNotFound:
|
|
165
|
+
# doctor must still report something useful when locate fails.
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
results = doctor_mod.run_all(css)
|
|
169
|
+
for r in results:
|
|
170
|
+
print(r.render())
|
|
171
|
+
return 0 if doctor_mod.all_passed(results) else 1
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def main(argv: list[str] | None = None) -> int:
|
|
175
|
+
parser = _build_parser()
|
|
176
|
+
args = parser.parse_args(argv)
|
|
177
|
+
if args.command == "set":
|
|
178
|
+
return cmd_set(args)
|
|
179
|
+
if args.command == "reset":
|
|
180
|
+
return cmd_reset(args)
|
|
181
|
+
if args.command == "status":
|
|
182
|
+
return cmd_status(args)
|
|
183
|
+
if args.command == "doctor":
|
|
184
|
+
return cmd_doctor(args)
|
|
185
|
+
parser.error(f"unknown command: {args.command}")
|
|
186
|
+
return 2 # unreachable, but keeps type-checkers happy
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Constants for hermes-font-scale.
|
|
2
|
+
|
|
3
|
+
Single source of truth for paths, ranges, and supported versions.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"VERSION",
|
|
12
|
+
"MIN_PX",
|
|
13
|
+
"MAX_PX",
|
|
14
|
+
"DEFAULT_BASE_PX",
|
|
15
|
+
"PX_DELTA_MAX",
|
|
16
|
+
"FONT_SIZE_REGEX",
|
|
17
|
+
"REPLACEMENT_TEMPLATE",
|
|
18
|
+
"BACKUP_SUFFIX",
|
|
19
|
+
"SUPPORTED_HERMES_MAJOR",
|
|
20
|
+
"CSS_RELATIVE_PATH_COMPONENTS",
|
|
21
|
+
"WINDOWS_SEARCH_PATHS",
|
|
22
|
+
"MACOS_SEARCH_PATHS",
|
|
23
|
+
"LINUX_SEARCH_PATHS",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
VERSION = "0.1.1"
|
|
27
|
+
|
|
28
|
+
# Font size range (px). Outside this range we reject with a clear error.
|
|
29
|
+
MIN_PX = 10
|
|
30
|
+
MAX_PX = 32
|
|
31
|
+
|
|
32
|
+
# Original Hermes base font size (line 379 of globals.css).
|
|
33
|
+
DEFAULT_BASE_PX = 14
|
|
34
|
+
|
|
35
|
+
# Original max-min delta (18 - 14 = 4). We preserve this so the responsive
|
|
36
|
+
# scaling behavior remains identical, just shifted.
|
|
37
|
+
PX_DELTA_MAX = 4
|
|
38
|
+
|
|
39
|
+
# Regex matching the exact font-size clause from Hermes Desktop's globals.css.
|
|
40
|
+
# Captures: (1) base px, (2) unused (the calc body), (3) max px.
|
|
41
|
+
FONT_SIZE_REGEX = (
|
|
42
|
+
r"font-size\s*:\s*clamp\(\s*(\d+)px\s*,\s*"
|
|
43
|
+
r"calc\(\s*\d+px\s*\+\s*2\s*\*\s*\(\(100vw\s*-\s*1400px\)\s*/\s*400\)\s*\)\s*,\s*"
|
|
44
|
+
r"(\d+)px\s*\)"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Replacement template. Caller fills {base} and {max}.
|
|
48
|
+
REPLACEMENT_TEMPLATE = "font-size: clamp({base}px, calc({base}px + 2 * ((100vw - 1400px) / 400)), {max}px)"
|
|
49
|
+
|
|
50
|
+
BACKUP_SUFFIX = ".bak"
|
|
51
|
+
|
|
52
|
+
# Minimum Hermes major version we support (the @nous-research/ui package
|
|
53
|
+
# was extracted around this version).
|
|
54
|
+
SUPPORTED_HERMES_MAJOR = 1
|
|
55
|
+
|
|
56
|
+
# Relative path components from Hermes install root to globals.css.
|
|
57
|
+
# Each entry is a candidate (some installs unpack @nous-research/ui, others don't).
|
|
58
|
+
CSS_RELATIVE_CANDIDATES: list[tuple[str, ...]] = [
|
|
59
|
+
# Production installer (asar unpacked)
|
|
60
|
+
(
|
|
61
|
+
"resources", "app.asar.unpacked", "node_modules",
|
|
62
|
+
"@nous-research", "ui", "dist", "ui", "globals.css",
|
|
63
|
+
),
|
|
64
|
+
# Dev checkout
|
|
65
|
+
(
|
|
66
|
+
"apps", "desktop", "node_modules",
|
|
67
|
+
"@nous-research", "ui", "dist", "ui", "globals.css",
|
|
68
|
+
),
|
|
69
|
+
# Top-level dev checkout (monorepo root)
|
|
70
|
+
(
|
|
71
|
+
"node_modules", "@nous-research", "ui", "dist", "ui", "globals.css",
|
|
72
|
+
),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _join(*parts: str) -> Path:
|
|
77
|
+
return Path(*parts)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Windows search roots (relative to known locations).
|
|
81
|
+
WINDOWS_SEARCH_ROOTS: list[Path] = [
|
|
82
|
+
Path.home() / "AppData" / "Local" / "hermes",
|
|
83
|
+
Path("C:") / "Program Files" / "Hermes",
|
|
84
|
+
Path("C:") / "Program Files (x86)" / "Hermes",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
# macOS search roots.
|
|
88
|
+
MACOS_SEARCH_ROOTS: list[Path] = [
|
|
89
|
+
Path("/Applications/Hermes.app/Contents/Resources"),
|
|
90
|
+
Path.home() / "Applications" / "Hermes.app" / "Contents" / "Resources",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
# Linux search roots.
|
|
94
|
+
LINUX_SEARCH_ROOTS: list[Path] = [
|
|
95
|
+
Path.home() / ".local" / "share" / "hermes",
|
|
96
|
+
Path("/opt/hermes"),
|
|
97
|
+
Path("/usr/local/share/hermes"),
|
|
98
|
+
Path("/usr/share/hermes"),
|
|
99
|
+
]
|