yread 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.
- yread/__init__.py +3 -0
- yread/cli.py +173 -0
- yread/core.py +1269 -0
- yread/viewer.py +179 -0
- yread-0.1.0.dist-info/METADATA +254 -0
- yread-0.1.0.dist-info/RECORD +9 -0
- yread-0.1.0.dist-info/WHEEL +4 -0
- yread-0.1.0.dist-info/entry_points.txt +2 -0
- yread-0.1.0.dist-info/licenses/LICENSE +21 -0
yread/__init__.py
ADDED
yread/cli.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Command line entry point for yread."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from . import __version__, core, viewer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
CONFIG_DIR = Path.home() / ".yread"
|
|
13
|
+
CONFIG_FILE = CONFIG_DIR / "config.env"
|
|
14
|
+
|
|
15
|
+
CONFIG_KEYS = {
|
|
16
|
+
"PROVIDER",
|
|
17
|
+
"BASE_URL",
|
|
18
|
+
"API_KEY",
|
|
19
|
+
"MODEL",
|
|
20
|
+
"DOC_LANG",
|
|
21
|
+
"MAX_STEPS",
|
|
22
|
+
"MAX_TOPICS",
|
|
23
|
+
"CONCURRENCY",
|
|
24
|
+
"ENABLE_SHELL",
|
|
25
|
+
"OUTPUT_DIR",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _read_config() -> dict[str, str]:
|
|
30
|
+
if not CONFIG_FILE.exists():
|
|
31
|
+
return {}
|
|
32
|
+
return core._parse_env_file(CONFIG_FILE)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _write_config(values: dict[str, str]) -> None:
|
|
36
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
lines = [
|
|
38
|
+
"# yread local configuration",
|
|
39
|
+
"# Edit with `yread config set KEY VALUE` or by changing this file.",
|
|
40
|
+
]
|
|
41
|
+
for key in sorted(values):
|
|
42
|
+
lines.append(f"{key}={values[key]}")
|
|
43
|
+
CONFIG_FILE.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _build_generate_parser() -> argparse.ArgumentParser:
|
|
47
|
+
return core.build_arg_parser()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
51
|
+
parser = argparse.ArgumentParser(
|
|
52
|
+
prog="yread",
|
|
53
|
+
description="Turn a local repository into a lightweight structured wiki.",
|
|
54
|
+
)
|
|
55
|
+
sub = parser.add_subparsers(dest="command")
|
|
56
|
+
|
|
57
|
+
generate = sub.add_parser("generate", help="Generate or resume a repo wiki")
|
|
58
|
+
for action in _build_generate_parser()._actions:
|
|
59
|
+
if action.dest == "help":
|
|
60
|
+
continue
|
|
61
|
+
generate._add_action(action)
|
|
62
|
+
|
|
63
|
+
browse = sub.add_parser("browse", help="Open a generated wiki in the browser")
|
|
64
|
+
browse.add_argument("wiki_dir", nargs="?", help="Wiki root or version directory")
|
|
65
|
+
browse.add_argument("--host", default="localhost", help="Host to bind")
|
|
66
|
+
browse.add_argument("--port", type=int, default=8000)
|
|
67
|
+
browse.add_argument("--repo", default=None, help="Source repository for source links")
|
|
68
|
+
|
|
69
|
+
sub.add_parser("version", help="Print the version number")
|
|
70
|
+
|
|
71
|
+
config = sub.add_parser("config", help=f"Manage {CONFIG_FILE}")
|
|
72
|
+
config_sub = config.add_subparsers(dest="config_command")
|
|
73
|
+
|
|
74
|
+
config_sub.add_parser("init", help="Interactively set up the config file")
|
|
75
|
+
config_sub.add_parser("path", help="Print the config file path")
|
|
76
|
+
config_sub.add_parser("show", help="Print current config")
|
|
77
|
+
|
|
78
|
+
set_cmd = config_sub.add_parser("set", help="Set one config value")
|
|
79
|
+
set_cmd.add_argument("key", choices=sorted(CONFIG_KEYS))
|
|
80
|
+
set_cmd.add_argument("value")
|
|
81
|
+
|
|
82
|
+
unset_cmd = config_sub.add_parser("unset", help="Remove one config value")
|
|
83
|
+
unset_cmd.add_argument("key", choices=sorted(CONFIG_KEYS))
|
|
84
|
+
|
|
85
|
+
return parser
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
INIT_PROMPTS = [
|
|
89
|
+
("PROVIDER", "Provider [minimax-cn/deepseek/openai-compatible]", "openai-compatible"),
|
|
90
|
+
("BASE_URL", "OpenAI-compatible /v1 endpoint", ""),
|
|
91
|
+
("API_KEY", "API key", ""),
|
|
92
|
+
("MODEL", "Model name", ""),
|
|
93
|
+
("DOC_LANG", "Documentation language code [zh/en]", "en"),
|
|
94
|
+
("OUTPUT_DIR", "Output directory (blank = <repo>/.yread/wiki)", ""),
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _run_config_init() -> int:
|
|
99
|
+
values = _read_config()
|
|
100
|
+
print(f"Configuring {CONFIG_FILE} (Enter keeps the shown value)\n")
|
|
101
|
+
for key, label, fallback in INIT_PROMPTS:
|
|
102
|
+
current = values.get(key, fallback)
|
|
103
|
+
suffix = f" [{current}]" if current else ""
|
|
104
|
+
entered = input(f"{label}{suffix}: ").strip()
|
|
105
|
+
chosen = entered or current
|
|
106
|
+
if chosen:
|
|
107
|
+
values[key] = chosen
|
|
108
|
+
else:
|
|
109
|
+
values.pop(key, None)
|
|
110
|
+
_write_config(values)
|
|
111
|
+
print(f"\nwrote {CONFIG_FILE}")
|
|
112
|
+
return 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _run_config(args: argparse.Namespace) -> int:
|
|
116
|
+
command = args.config_command or "show"
|
|
117
|
+
if command == "init":
|
|
118
|
+
return _run_config_init()
|
|
119
|
+
if command == "path":
|
|
120
|
+
print(CONFIG_FILE)
|
|
121
|
+
return 0
|
|
122
|
+
values = _read_config()
|
|
123
|
+
if command == "show":
|
|
124
|
+
if not values:
|
|
125
|
+
print(f"# no config yet: {CONFIG_FILE}")
|
|
126
|
+
return 0
|
|
127
|
+
for key in sorted(values):
|
|
128
|
+
print(f"{key}={values[key]}")
|
|
129
|
+
return 0
|
|
130
|
+
if command == "set":
|
|
131
|
+
values[args.key] = args.value
|
|
132
|
+
_write_config(values)
|
|
133
|
+
print(CONFIG_FILE)
|
|
134
|
+
return 0
|
|
135
|
+
if command == "unset":
|
|
136
|
+
values.pop(args.key, None)
|
|
137
|
+
_write_config(values)
|
|
138
|
+
print(CONFIG_FILE)
|
|
139
|
+
return 0
|
|
140
|
+
raise SystemExit(f"unknown config command: {command}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _run_browse(args: argparse.Namespace) -> int:
|
|
144
|
+
viewer_args = []
|
|
145
|
+
if args.wiki_dir:
|
|
146
|
+
viewer_args.append(args.wiki_dir)
|
|
147
|
+
viewer_args.extend(["--host", args.host, "--port", str(args.port)])
|
|
148
|
+
if args.repo:
|
|
149
|
+
viewer_args.extend(["--repo", args.repo])
|
|
150
|
+
viewer.main(viewer_args)
|
|
151
|
+
return 0
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def main(argv: list[str] | None = None) -> int:
|
|
155
|
+
parser = _build_parser()
|
|
156
|
+
args = parser.parse_args(list(sys.argv[1:] if argv is None else argv))
|
|
157
|
+
if args.command == "version":
|
|
158
|
+
print(f"yread {__version__}")
|
|
159
|
+
return 0
|
|
160
|
+
if args.command == "config":
|
|
161
|
+
return _run_config(args)
|
|
162
|
+
if args.command == "browse":
|
|
163
|
+
return _run_browse(args)
|
|
164
|
+
if args.command == "generate":
|
|
165
|
+
config = core.config_from_args(args, config_files=[CONFIG_FILE])
|
|
166
|
+
core.run_generate(args, config)
|
|
167
|
+
return 0
|
|
168
|
+
parser.print_help()
|
|
169
|
+
return 0
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
raise SystemExit(main())
|