yuho 5.0.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.
- yuho/__init__.py +16 -0
- yuho/ast/__init__.py +196 -0
- yuho/ast/builder.py +926 -0
- yuho/ast/constant_folder.py +280 -0
- yuho/ast/dead_code.py +199 -0
- yuho/ast/exhaustiveness.py +503 -0
- yuho/ast/nodes.py +907 -0
- yuho/ast/overlap.py +291 -0
- yuho/ast/reachability.py +293 -0
- yuho/ast/scope_analysis.py +490 -0
- yuho/ast/transformer.py +490 -0
- yuho/ast/type_check.py +471 -0
- yuho/ast/type_inference.py +425 -0
- yuho/ast/visitor.py +239 -0
- yuho/cli/__init__.py +14 -0
- yuho/cli/commands/__init__.py +1 -0
- yuho/cli/commands/api.py +431 -0
- yuho/cli/commands/ast_viz.py +334 -0
- yuho/cli/commands/check.py +218 -0
- yuho/cli/commands/config.py +311 -0
- yuho/cli/commands/contribute.py +122 -0
- yuho/cli/commands/diff.py +487 -0
- yuho/cli/commands/explain.py +240 -0
- yuho/cli/commands/fmt.py +253 -0
- yuho/cli/commands/generate.py +316 -0
- yuho/cli/commands/graph.py +410 -0
- yuho/cli/commands/init.py +120 -0
- yuho/cli/commands/library.py +656 -0
- yuho/cli/commands/lint.py +503 -0
- yuho/cli/commands/lsp.py +36 -0
- yuho/cli/commands/preview.py +377 -0
- yuho/cli/commands/repl.py +444 -0
- yuho/cli/commands/serve.py +44 -0
- yuho/cli/commands/test.py +528 -0
- yuho/cli/commands/transpile.py +121 -0
- yuho/cli/commands/wizard.py +370 -0
- yuho/cli/completions.py +182 -0
- yuho/cli/error_formatter.py +193 -0
- yuho/cli/main.py +1064 -0
- yuho/config/__init__.py +46 -0
- yuho/config/loader.py +235 -0
- yuho/config/mask.py +194 -0
- yuho/config/schema.py +147 -0
- yuho/library/__init__.py +84 -0
- yuho/library/index.py +328 -0
- yuho/library/install.py +699 -0
- yuho/library/lockfile.py +330 -0
- yuho/library/package.py +421 -0
- yuho/library/resolver.py +791 -0
- yuho/library/signature.py +335 -0
- yuho/llm/__init__.py +45 -0
- yuho/llm/config.py +75 -0
- yuho/llm/factory.py +123 -0
- yuho/llm/prompts.py +146 -0
- yuho/llm/providers.py +383 -0
- yuho/llm/utils.py +470 -0
- yuho/lsp/__init__.py +14 -0
- yuho/lsp/code_action_handler.py +518 -0
- yuho/lsp/completion_handler.py +85 -0
- yuho/lsp/diagnostics.py +100 -0
- yuho/lsp/hover_handler.py +130 -0
- yuho/lsp/server.py +1425 -0
- yuho/mcp/__init__.py +10 -0
- yuho/mcp/server.py +1452 -0
- yuho/parser/__init__.py +8 -0
- yuho/parser/source_location.py +108 -0
- yuho/parser/wrapper.py +311 -0
- yuho/testing/__init__.py +48 -0
- yuho/testing/coverage.py +274 -0
- yuho/testing/fixtures.py +263 -0
- yuho/transpile/__init__.py +52 -0
- yuho/transpile/alloy_transpiler.py +546 -0
- yuho/transpile/base.py +100 -0
- yuho/transpile/blocks_transpiler.py +338 -0
- yuho/transpile/english_transpiler.py +470 -0
- yuho/transpile/graphql_transpiler.py +404 -0
- yuho/transpile/json_transpiler.py +217 -0
- yuho/transpile/jsonld_transpiler.py +250 -0
- yuho/transpile/latex_preamble.py +161 -0
- yuho/transpile/latex_transpiler.py +406 -0
- yuho/transpile/latex_utils.py +206 -0
- yuho/transpile/mermaid_transpiler.py +357 -0
- yuho/transpile/registry.py +275 -0
- yuho/verify/__init__.py +43 -0
- yuho/verify/alloy.py +352 -0
- yuho/verify/combined.py +218 -0
- yuho/verify/z3_solver.py +1155 -0
- yuho-5.0.0.dist-info/METADATA +186 -0
- yuho-5.0.0.dist-info/RECORD +91 -0
- yuho-5.0.0.dist-info/WHEEL +4 -0
- yuho-5.0.0.dist-info/entry_points.txt +2 -0
yuho/cli/main.py
ADDED
|
@@ -0,0 +1,1064 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main CLI entry point using Click.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional, List
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from yuho import __version__
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _detect_color_support() -> bool:
|
|
16
|
+
"""
|
|
17
|
+
Auto-detect terminal color support.
|
|
18
|
+
|
|
19
|
+
Checks for:
|
|
20
|
+
- TTY attached to stdout
|
|
21
|
+
- NO_COLOR environment variable (force disable)
|
|
22
|
+
- FORCE_COLOR environment variable (force enable)
|
|
23
|
+
- TERM environment variable
|
|
24
|
+
"""
|
|
25
|
+
# NO_COLOR spec: https://no-color.org/
|
|
26
|
+
if os.environ.get("NO_COLOR"):
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
# FORCE_COLOR always wins
|
|
30
|
+
if os.environ.get("FORCE_COLOR"):
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
# Check if stdout is a TTY
|
|
34
|
+
if not hasattr(sys.stdout, "isatty") or not sys.stdout.isatty():
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
# Check TERM variable
|
|
38
|
+
term = os.environ.get("TERM", "")
|
|
39
|
+
if term == "dumb":
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Click context settings
|
|
46
|
+
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@click.group(context_settings=CONTEXT_SETTINGS)
|
|
50
|
+
@click.version_option(version=__version__, prog_name="yuho")
|
|
51
|
+
@click.option("-v", "--verbose", is_flag=True, help="Enable verbose output")
|
|
52
|
+
@click.option(
|
|
53
|
+
"--color/--no-color",
|
|
54
|
+
"use_color",
|
|
55
|
+
default=None,
|
|
56
|
+
help="Force color output on/off (auto-detected by default)"
|
|
57
|
+
)
|
|
58
|
+
@click.option(
|
|
59
|
+
"-q", "--quiet",
|
|
60
|
+
is_flag=True,
|
|
61
|
+
help="Suppress non-error output"
|
|
62
|
+
)
|
|
63
|
+
@click.pass_context
|
|
64
|
+
def cli(ctx: click.Context, verbose: bool, use_color: Optional[bool], quiet: bool) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Yuho - A domain-specific language for encoding legal statutes.
|
|
67
|
+
|
|
68
|
+
Use 'yuho <command> --help' for command-specific help.
|
|
69
|
+
"""
|
|
70
|
+
ctx.ensure_object(dict)
|
|
71
|
+
ctx.obj["verbose"] = verbose and not quiet # Quiet overrides verbose
|
|
72
|
+
ctx.obj["quiet"] = quiet
|
|
73
|
+
|
|
74
|
+
# Determine color setting
|
|
75
|
+
if use_color is None:
|
|
76
|
+
# Auto-detect
|
|
77
|
+
ctx.obj["color"] = _detect_color_support()
|
|
78
|
+
else:
|
|
79
|
+
ctx.obj["color"] = use_color
|
|
80
|
+
|
|
81
|
+
# Set global color state for error_formatter
|
|
82
|
+
from yuho.cli import error_formatter
|
|
83
|
+
error_formatter.COLOR_ENABLED = ctx.obj["color"]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# =============================================================================
|
|
87
|
+
# Check command
|
|
88
|
+
# =============================================================================
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@cli.command()
|
|
92
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
93
|
+
@click.option("--json", "json_output", is_flag=True, help="Output errors as JSON")
|
|
94
|
+
@click.option("--explain-error", "explain_errors", is_flag=True,
|
|
95
|
+
help="Show detailed explanations for errors with common causes and fixes")
|
|
96
|
+
@click.pass_context
|
|
97
|
+
def check(ctx: click.Context, file: str, json_output: bool, explain_errors: bool) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Parse and validate a Yuho source file.
|
|
100
|
+
|
|
101
|
+
Runs syntax checking and semantic analysis, reporting any errors found.
|
|
102
|
+
"""
|
|
103
|
+
from yuho.cli.commands.check import run_check
|
|
104
|
+
run_check(file, json_output=json_output, verbose=ctx.obj["verbose"], explain_errors=explain_errors)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# =============================================================================
|
|
108
|
+
# AST command
|
|
109
|
+
# =============================================================================
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@cli.command()
|
|
113
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
114
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
|
115
|
+
@click.option("--tree", "show_tree", is_flag=True, default=True, help="Show tree visualization (default)")
|
|
116
|
+
@click.option("--stats", is_flag=True, help="Show AST statistics")
|
|
117
|
+
@click.option("--depth", type=int, default=0, help="Max depth (0 = unlimited)")
|
|
118
|
+
@click.option("--ascii", "no_unicode", is_flag=True, help="Use ASCII-only characters")
|
|
119
|
+
@click.pass_context
|
|
120
|
+
def ast(
|
|
121
|
+
ctx: click.Context,
|
|
122
|
+
file: str,
|
|
123
|
+
output: Optional[str],
|
|
124
|
+
show_tree: bool,
|
|
125
|
+
stats: bool,
|
|
126
|
+
depth: int,
|
|
127
|
+
no_unicode: bool,
|
|
128
|
+
) -> None:
|
|
129
|
+
"""
|
|
130
|
+
Visualize AST structure as tree.
|
|
131
|
+
|
|
132
|
+
Displays the abstract syntax tree of a Yuho statute using
|
|
133
|
+
tree-like ASCII art in the terminal.
|
|
134
|
+
|
|
135
|
+
Examples:
|
|
136
|
+
yuho ast statute.yh
|
|
137
|
+
yuho ast statute.yh --stats
|
|
138
|
+
yuho ast statute.yh --ascii -o tree.txt
|
|
139
|
+
"""
|
|
140
|
+
from yuho.cli.commands.ast_viz import run_ast_viz
|
|
141
|
+
run_ast_viz(
|
|
142
|
+
file=file,
|
|
143
|
+
output=output,
|
|
144
|
+
stats=stats,
|
|
145
|
+
depth=depth,
|
|
146
|
+
no_unicode=no_unicode,
|
|
147
|
+
verbose=ctx.obj["verbose"],
|
|
148
|
+
color=ctx.obj["color"],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# =============================================================================
|
|
153
|
+
# Transpile command
|
|
154
|
+
# =============================================================================
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@cli.command()
|
|
158
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
159
|
+
@click.option(
|
|
160
|
+
"-t", "--target",
|
|
161
|
+
type=click.Choice(["json", "jsonld", "english", "latex", "mermaid", "alloy", "graphql", "blocks"], case_sensitive=False),
|
|
162
|
+
default="json",
|
|
163
|
+
help="Transpilation target format"
|
|
164
|
+
)
|
|
165
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
|
166
|
+
@click.option("--dir", "output_dir", type=click.Path(), help="Output directory for multiple files")
|
|
167
|
+
@click.option("--all", "all_targets", is_flag=True, help="Generate all targets")
|
|
168
|
+
@click.option("--json", "json_output", is_flag=True, help="Output metadata as JSON")
|
|
169
|
+
@click.pass_context
|
|
170
|
+
def transpile(
|
|
171
|
+
ctx: click.Context,
|
|
172
|
+
file: str,
|
|
173
|
+
target: str,
|
|
174
|
+
output: Optional[str],
|
|
175
|
+
output_dir: Optional[str],
|
|
176
|
+
all_targets: bool,
|
|
177
|
+
json_output: bool
|
|
178
|
+
) -> None:
|
|
179
|
+
"""
|
|
180
|
+
Transpile a Yuho source file to another format.
|
|
181
|
+
|
|
182
|
+
Supported targets: json, jsonld, english, latex, mermaid, alloy, graphql, blocks
|
|
183
|
+
"""
|
|
184
|
+
from yuho.cli.commands.transpile import run_transpile
|
|
185
|
+
run_transpile(
|
|
186
|
+
file,
|
|
187
|
+
target=target,
|
|
188
|
+
output=output,
|
|
189
|
+
output_dir=output_dir,
|
|
190
|
+
all_targets=all_targets,
|
|
191
|
+
json_output=json_output,
|
|
192
|
+
verbose=ctx.obj["verbose"]
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# =============================================================================
|
|
197
|
+
# Preview command
|
|
198
|
+
# =============================================================================
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@cli.command()
|
|
202
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
203
|
+
@click.option(
|
|
204
|
+
"-t", "--target",
|
|
205
|
+
type=click.Choice(["english", "mermaid"], case_sensitive=False),
|
|
206
|
+
default="english",
|
|
207
|
+
help="Preview format (english or mermaid)"
|
|
208
|
+
)
|
|
209
|
+
@click.option("-p", "--port", type=int, default=8000, help="Server port")
|
|
210
|
+
@click.option("--no-browser", is_flag=True, help="Don't auto-open browser")
|
|
211
|
+
@click.pass_context
|
|
212
|
+
def preview(
|
|
213
|
+
ctx: click.Context,
|
|
214
|
+
file: str,
|
|
215
|
+
target: str,
|
|
216
|
+
port: int,
|
|
217
|
+
no_browser: bool,
|
|
218
|
+
) -> None:
|
|
219
|
+
"""
|
|
220
|
+
Live preview with auto-reload on file changes.
|
|
221
|
+
|
|
222
|
+
Watches the file for changes, transpiles to the target format,
|
|
223
|
+
and serves a live-reloading preview in your browser.
|
|
224
|
+
|
|
225
|
+
Examples:
|
|
226
|
+
yuho preview statute.yh
|
|
227
|
+
yuho preview statute.yh --target mermaid
|
|
228
|
+
yuho preview statute.yh --port 3000 --no-browser
|
|
229
|
+
"""
|
|
230
|
+
from yuho.cli.commands.preview import run_preview
|
|
231
|
+
run_preview(
|
|
232
|
+
file=file,
|
|
233
|
+
target=target.lower(),
|
|
234
|
+
port=port,
|
|
235
|
+
no_browser=no_browser,
|
|
236
|
+
verbose=ctx.obj["verbose"],
|
|
237
|
+
color=ctx.obj["color"],
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# =============================================================================
|
|
242
|
+
# REPL command
|
|
243
|
+
# =============================================================================
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@cli.command()
|
|
247
|
+
@click.pass_context
|
|
248
|
+
def repl(ctx: click.Context) -> None:
|
|
249
|
+
"""
|
|
250
|
+
Start interactive REPL for statute experimentation.
|
|
251
|
+
|
|
252
|
+
The REPL provides an interactive environment for:
|
|
253
|
+
- Parsing and validating Yuho code snippets
|
|
254
|
+
- Transpiling to various targets (json, english, mermaid, etc.)
|
|
255
|
+
- Exploring statute definitions and AST structure
|
|
256
|
+
- Testing legal logic interactively
|
|
257
|
+
|
|
258
|
+
Type 'help' within the REPL for available commands.
|
|
259
|
+
"""
|
|
260
|
+
from yuho.cli.commands.repl import run_repl
|
|
261
|
+
sys.exit(run_repl(color=ctx.obj["color"], verbose=ctx.obj["verbose"]))
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# =============================================================================
|
|
265
|
+
# Explain command
|
|
266
|
+
# =============================================================================
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@cli.command()
|
|
270
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
271
|
+
@click.option("-s", "--section", help="Explain specific section only")
|
|
272
|
+
@click.option("-i", "--interactive", is_flag=True, help="Interactive REPL mode")
|
|
273
|
+
@click.option("--provider", type=click.Choice(["ollama", "huggingface", "openai", "anthropic"]),
|
|
274
|
+
help="LLM provider to use")
|
|
275
|
+
@click.option("--model", help="Model name to use")
|
|
276
|
+
@click.option("--stream/--no-stream", "stream", default=True,
|
|
277
|
+
help="Enable/disable streaming output for real-time response")
|
|
278
|
+
@click.pass_context
|
|
279
|
+
def explain(
|
|
280
|
+
ctx: click.Context,
|
|
281
|
+
file: str,
|
|
282
|
+
section: Optional[str],
|
|
283
|
+
interactive: bool,
|
|
284
|
+
provider: Optional[str],
|
|
285
|
+
model: Optional[str],
|
|
286
|
+
stream: bool,
|
|
287
|
+
) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Generate natural language explanation of a Yuho file.
|
|
290
|
+
|
|
291
|
+
Uses LLM to explain statutes in plain language.
|
|
292
|
+
"""
|
|
293
|
+
from yuho.cli.commands.explain import run_explain
|
|
294
|
+
run_explain(
|
|
295
|
+
file,
|
|
296
|
+
section=section,
|
|
297
|
+
interactive=interactive,
|
|
298
|
+
provider=provider,
|
|
299
|
+
model=model,
|
|
300
|
+
verbose=ctx.obj["verbose"],
|
|
301
|
+
stream=stream,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
# =============================================================================
|
|
306
|
+
# Diff command
|
|
307
|
+
# =============================================================================
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@cli.command()
|
|
311
|
+
@click.argument("file1", type=click.Path(exists=True))
|
|
312
|
+
@click.argument("file2", type=click.Path(exists=True))
|
|
313
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
314
|
+
@click.pass_context
|
|
315
|
+
def diff(ctx: click.Context, file1: str, file2: str, json_output: bool) -> None:
|
|
316
|
+
"""
|
|
317
|
+
Compare two Yuho files and show semantic differences.
|
|
318
|
+
|
|
319
|
+
Shows added, removed, and modified statutes, definitions, elements,
|
|
320
|
+
penalties, and illustrations between two versions.
|
|
321
|
+
|
|
322
|
+
Examples:
|
|
323
|
+
yuho diff old.yh new.yh
|
|
324
|
+
yuho diff v1/statute.yh v2/statute.yh --json
|
|
325
|
+
"""
|
|
326
|
+
from yuho.cli.commands.diff import run_diff
|
|
327
|
+
run_diff(
|
|
328
|
+
file1,
|
|
329
|
+
file2,
|
|
330
|
+
json_output=json_output,
|
|
331
|
+
verbose=ctx.obj["verbose"],
|
|
332
|
+
color=ctx.obj["color"],
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
# =============================================================================
|
|
337
|
+
# Graph command
|
|
338
|
+
# =============================================================================
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@cli.command()
|
|
342
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
343
|
+
@click.option(
|
|
344
|
+
"-f", "--format",
|
|
345
|
+
type=click.Choice(["dot", "mermaid"], case_sensitive=False),
|
|
346
|
+
default="mermaid",
|
|
347
|
+
help="Output format"
|
|
348
|
+
)
|
|
349
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
|
350
|
+
@click.pass_context
|
|
351
|
+
def graph(ctx: click.Context, file: str, format: str, output: Optional[str]) -> None:
|
|
352
|
+
"""
|
|
353
|
+
Visualize statute dependencies as a graph.
|
|
354
|
+
|
|
355
|
+
Generates a dependency graph showing:
|
|
356
|
+
- Statute cross-references
|
|
357
|
+
- Import relationships
|
|
358
|
+
- Type and function definitions
|
|
359
|
+
|
|
360
|
+
Examples:
|
|
361
|
+
yuho graph statute.yh
|
|
362
|
+
yuho graph statute.yh --format dot -o deps.dot
|
|
363
|
+
yuho graph statute.yh --format mermaid > deps.md
|
|
364
|
+
"""
|
|
365
|
+
from yuho.cli.commands.graph import run_graph
|
|
366
|
+
run_graph(
|
|
367
|
+
file,
|
|
368
|
+
format=format,
|
|
369
|
+
output=output,
|
|
370
|
+
verbose=ctx.obj["verbose"],
|
|
371
|
+
color=ctx.obj["color"],
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# =============================================================================
|
|
376
|
+
# Lint command
|
|
377
|
+
# =============================================================================
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
@cli.command()
|
|
381
|
+
@click.argument("files", nargs=-1, type=click.Path(exists=True), required=True)
|
|
382
|
+
@click.option("--rule", "-r", "rules", multiple=True, help="Specific rules to run")
|
|
383
|
+
@click.option("--exclude", "-e", "exclude_rules", multiple=True, help="Rules to exclude")
|
|
384
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
385
|
+
@click.option("--fix", is_flag=True, help="Auto-fix issues where possible")
|
|
386
|
+
@click.pass_context
|
|
387
|
+
def lint(
|
|
388
|
+
ctx: click.Context,
|
|
389
|
+
files: tuple,
|
|
390
|
+
rules: tuple,
|
|
391
|
+
exclude_rules: tuple,
|
|
392
|
+
json_output: bool,
|
|
393
|
+
fix: bool,
|
|
394
|
+
) -> None:
|
|
395
|
+
"""
|
|
396
|
+
Check Yuho files for style and best practice issues.
|
|
397
|
+
|
|
398
|
+
Analyzes files for:
|
|
399
|
+
- Missing statute titles, elements, or penalties
|
|
400
|
+
- Naming convention violations
|
|
401
|
+
- Unused definitions
|
|
402
|
+
- Duplicate section numbers
|
|
403
|
+
|
|
404
|
+
Examples:
|
|
405
|
+
yuho lint statute.yh
|
|
406
|
+
yuho lint *.yh --exclude missing-penalty
|
|
407
|
+
yuho lint src/ --json
|
|
408
|
+
"""
|
|
409
|
+
from yuho.cli.commands.lint import run_lint
|
|
410
|
+
run_lint(
|
|
411
|
+
list(files),
|
|
412
|
+
rules=list(rules) if rules else None,
|
|
413
|
+
exclude_rules=list(exclude_rules) if exclude_rules else None,
|
|
414
|
+
json_output=json_output,
|
|
415
|
+
verbose=ctx.obj["verbose"],
|
|
416
|
+
color=ctx.obj["color"],
|
|
417
|
+
fix=fix,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# =============================================================================
|
|
422
|
+
# API command
|
|
423
|
+
# =============================================================================
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
@cli.command()
|
|
427
|
+
@click.option("-p", "--port", type=int, default=8080, help="Port to listen on")
|
|
428
|
+
@click.option("--host", default="127.0.0.1", help="Host to bind to")
|
|
429
|
+
@click.pass_context
|
|
430
|
+
def api(ctx: click.Context, port: int, host: str) -> None:
|
|
431
|
+
"""
|
|
432
|
+
Start the REST API server for remote operations.
|
|
433
|
+
|
|
434
|
+
Provides HTTP endpoints for:
|
|
435
|
+
- Parsing and validating Yuho source code
|
|
436
|
+
- Transpiling to various formats
|
|
437
|
+
- Running lint checks
|
|
438
|
+
|
|
439
|
+
Examples:
|
|
440
|
+
yuho api
|
|
441
|
+
yuho api --port 3000 --host 0.0.0.0
|
|
442
|
+
"""
|
|
443
|
+
from yuho.cli.commands.api import run_api
|
|
444
|
+
run_api(
|
|
445
|
+
host=host,
|
|
446
|
+
port=port,
|
|
447
|
+
verbose=ctx.obj["verbose"],
|
|
448
|
+
color=ctx.obj["color"],
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
# =============================================================================
|
|
453
|
+
# Generate command
|
|
454
|
+
# =============================================================================
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
@cli.command()
|
|
458
|
+
@click.argument("section")
|
|
459
|
+
@click.option("-t", "--title", required=True, help="Statute title")
|
|
460
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
|
461
|
+
@click.option(
|
|
462
|
+
"--template",
|
|
463
|
+
type=click.Choice(["standard", "minimal", "full"], case_sensitive=False),
|
|
464
|
+
default="standard",
|
|
465
|
+
help="Scaffold template type"
|
|
466
|
+
)
|
|
467
|
+
@click.option("--no-definitions", is_flag=True, help="Skip definitions block")
|
|
468
|
+
@click.option("--no-penalty", is_flag=True, help="Skip penalty block")
|
|
469
|
+
@click.option("--no-illustrations", is_flag=True, help="Skip illustrations block")
|
|
470
|
+
@click.option("-f", "--force", is_flag=True, help="Overwrite existing file")
|
|
471
|
+
@click.pass_context
|
|
472
|
+
def generate(
|
|
473
|
+
ctx: click.Context,
|
|
474
|
+
section: str,
|
|
475
|
+
title: str,
|
|
476
|
+
output: Optional[str],
|
|
477
|
+
template: str,
|
|
478
|
+
no_definitions: bool,
|
|
479
|
+
no_penalty: bool,
|
|
480
|
+
no_illustrations: bool,
|
|
481
|
+
force: bool,
|
|
482
|
+
) -> None:
|
|
483
|
+
"""
|
|
484
|
+
Generate statute scaffold with proper structure.
|
|
485
|
+
|
|
486
|
+
Creates a boilerplate .yh file with the specified section number
|
|
487
|
+
and title. Fill in the TODO markers to complete your statute.
|
|
488
|
+
|
|
489
|
+
Examples:
|
|
490
|
+
yuho generate 500 --title "Theft"
|
|
491
|
+
yuho generate s299 --title "Culpable Homicide" --template full
|
|
492
|
+
yuho generate 420 -t "Cheating" -o cheating.yh
|
|
493
|
+
"""
|
|
494
|
+
from yuho.cli.commands.generate import run_generate
|
|
495
|
+
run_generate(
|
|
496
|
+
section=section,
|
|
497
|
+
title=title,
|
|
498
|
+
output=output,
|
|
499
|
+
template=template.lower(),
|
|
500
|
+
no_definitions=no_definitions,
|
|
501
|
+
no_penalty=no_penalty,
|
|
502
|
+
no_illustrations=no_illustrations,
|
|
503
|
+
force=force,
|
|
504
|
+
verbose=ctx.obj["verbose"],
|
|
505
|
+
color=ctx.obj["color"],
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
# =============================================================================
|
|
510
|
+
# Wizard command
|
|
511
|
+
# =============================================================================
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@cli.command()
|
|
515
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
|
516
|
+
@click.option("--section", help="Pre-set section number")
|
|
517
|
+
@click.option("--title", help="Pre-set statute title")
|
|
518
|
+
@click.pass_context
|
|
519
|
+
def wizard(
|
|
520
|
+
ctx: click.Context,
|
|
521
|
+
output: Optional[str],
|
|
522
|
+
section: Optional[str],
|
|
523
|
+
title: Optional[str],
|
|
524
|
+
) -> None:
|
|
525
|
+
"""
|
|
526
|
+
Interactive wizard for statute creation.
|
|
527
|
+
|
|
528
|
+
Guides you through building a Yuho statute step-by-step using
|
|
529
|
+
inquirer-style prompts. Generates valid .yh source files.
|
|
530
|
+
|
|
531
|
+
Examples:
|
|
532
|
+
yuho wizard
|
|
533
|
+
yuho wizard -o my_statute.yh
|
|
534
|
+
yuho wizard --section 299 --title "Culpable Homicide"
|
|
535
|
+
"""
|
|
536
|
+
from yuho.cli.commands.wizard import run_wizard
|
|
537
|
+
run_wizard(
|
|
538
|
+
output=output,
|
|
539
|
+
section=section,
|
|
540
|
+
title=title,
|
|
541
|
+
verbose=ctx.obj["verbose"],
|
|
542
|
+
color=ctx.obj["color"],
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
# =============================================================================
|
|
547
|
+
# Serve command
|
|
548
|
+
# =============================================================================
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
@cli.command()
|
|
552
|
+
@click.option("-p", "--port", type=int, default=8080, help="Port to listen on")
|
|
553
|
+
@click.option("--host", default="127.0.0.1", help="Host to bind to")
|
|
554
|
+
@click.option("--stdio", is_flag=True, help="Use stdio transport (for editor integration)")
|
|
555
|
+
@click.pass_context
|
|
556
|
+
def serve(ctx: click.Context, port: int, host: str, stdio: bool) -> None:
|
|
557
|
+
"""
|
|
558
|
+
Start the MCP (Model Context Protocol) server.
|
|
559
|
+
|
|
560
|
+
Exposes Yuho functionality to AI assistants and editors.
|
|
561
|
+
"""
|
|
562
|
+
from yuho.cli.commands.serve import run_serve
|
|
563
|
+
run_serve(port=port, host=host, stdio=stdio, verbose=ctx.obj["verbose"])
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
# =============================================================================
|
|
567
|
+
# Contribute command
|
|
568
|
+
# =============================================================================
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
@cli.command()
|
|
572
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
573
|
+
@click.option("--package", is_flag=True, help="Create distributable .yhpkg archive")
|
|
574
|
+
@click.option("-o", "--output", type=click.Path(), help="Output path for package")
|
|
575
|
+
@click.pass_context
|
|
576
|
+
def contribute(ctx: click.Context, file: str, package: bool, output: Optional[str]) -> None:
|
|
577
|
+
"""
|
|
578
|
+
Validate a statute file for contribution to the library.
|
|
579
|
+
|
|
580
|
+
Checks that the file parses correctly and has associated tests.
|
|
581
|
+
"""
|
|
582
|
+
from yuho.cli.commands.contribute import run_contribute
|
|
583
|
+
run_contribute(file, package=package, output=output, verbose=ctx.obj["verbose"])
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
# =============================================================================
|
|
587
|
+
# Init command
|
|
588
|
+
# =============================================================================
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
@cli.command()
|
|
592
|
+
@click.argument("name", required=False)
|
|
593
|
+
@click.option("-d", "--dir", "directory", type=click.Path(), help="Directory to create project in")
|
|
594
|
+
@click.pass_context
|
|
595
|
+
def init(ctx: click.Context, name: Optional[str], directory: Optional[str]) -> None:
|
|
596
|
+
"""
|
|
597
|
+
Initialize a new Yuho statute project.
|
|
598
|
+
|
|
599
|
+
Creates a directory structure with template files.
|
|
600
|
+
"""
|
|
601
|
+
from yuho.cli.commands.init import run_init
|
|
602
|
+
run_init(name=name, directory=directory, verbose=ctx.obj["verbose"])
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
# =============================================================================
|
|
606
|
+
# Format command
|
|
607
|
+
# =============================================================================
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
@cli.command()
|
|
611
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
612
|
+
@click.option("-i", "--in-place", is_flag=True, help="Format file in place")
|
|
613
|
+
@click.option("--check", is_flag=True, help="Check if file is formatted (exit 1 if not)")
|
|
614
|
+
@click.pass_context
|
|
615
|
+
def fmt(ctx: click.Context, file: str, in_place: bool, check: bool) -> None:
|
|
616
|
+
"""
|
|
617
|
+
Format a Yuho source file.
|
|
618
|
+
|
|
619
|
+
Applies canonical formatting to the file.
|
|
620
|
+
"""
|
|
621
|
+
from yuho.cli.commands.fmt import run_fmt
|
|
622
|
+
run_fmt(file, in_place=in_place, check=check, verbose=ctx.obj["verbose"])
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
# =============================================================================
|
|
626
|
+
# Test command
|
|
627
|
+
# =============================================================================
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
@cli.command()
|
|
631
|
+
@click.argument("file", type=click.Path(exists=True), required=False)
|
|
632
|
+
@click.option("--all", "run_all", is_flag=True, help="Run all tests in directory")
|
|
633
|
+
@click.option("--json", "json_output", is_flag=True, help="Output results as JSON")
|
|
634
|
+
@click.option("--coverage", is_flag=True, help="Enable coverage tracking")
|
|
635
|
+
@click.option("--coverage-html", type=click.Path(), help="Generate HTML coverage report")
|
|
636
|
+
@click.pass_context
|
|
637
|
+
def test(
|
|
638
|
+
ctx: click.Context,
|
|
639
|
+
file: Optional[str],
|
|
640
|
+
run_all: bool,
|
|
641
|
+
json_output: bool,
|
|
642
|
+
coverage: bool,
|
|
643
|
+
coverage_html: Optional[str],
|
|
644
|
+
) -> None:
|
|
645
|
+
"""
|
|
646
|
+
Run tests for a Yuho statute file.
|
|
647
|
+
|
|
648
|
+
Looks for test_<filename>.yh or tests/<filename>_test.yh
|
|
649
|
+
|
|
650
|
+
Examples:
|
|
651
|
+
yuho test statute.yh
|
|
652
|
+
yuho test --all
|
|
653
|
+
yuho test --all --coverage
|
|
654
|
+
yuho test --all --coverage-html coverage.html
|
|
655
|
+
"""
|
|
656
|
+
from yuho.cli.commands.test import run_test
|
|
657
|
+
run_test(
|
|
658
|
+
file,
|
|
659
|
+
run_all=run_all,
|
|
660
|
+
json_output=json_output,
|
|
661
|
+
verbose=ctx.obj["verbose"],
|
|
662
|
+
coverage=coverage or bool(coverage_html),
|
|
663
|
+
coverage_html=coverage_html,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
# =============================================================================
|
|
668
|
+
# LSP command
|
|
669
|
+
# =============================================================================
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
@cli.command()
|
|
673
|
+
@click.option("--tcp", type=int, help="Start LSP server on TCP port")
|
|
674
|
+
@click.pass_context
|
|
675
|
+
def lsp(ctx: click.Context, tcp: Optional[int]) -> None:
|
|
676
|
+
"""
|
|
677
|
+
Start the Language Server Protocol server.
|
|
678
|
+
|
|
679
|
+
For editor integration (VS Code, Neovim, etc.).
|
|
680
|
+
"""
|
|
681
|
+
from yuho.cli.commands.lsp import run_lsp
|
|
682
|
+
run_lsp(tcp=tcp, verbose=ctx.obj["verbose"])
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
# =============================================================================
|
|
686
|
+
# Completion command
|
|
687
|
+
# =============================================================================
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
@cli.command()
|
|
691
|
+
@click.argument(
|
|
692
|
+
"shell",
|
|
693
|
+
type=click.Choice(["bash", "zsh", "fish"], case_sensitive=False),
|
|
694
|
+
)
|
|
695
|
+
@click.option(
|
|
696
|
+
"--install", "show_install",
|
|
697
|
+
is_flag=True,
|
|
698
|
+
help="Show installation instructions"
|
|
699
|
+
)
|
|
700
|
+
@click.pass_context
|
|
701
|
+
def completion(ctx: click.Context, shell: str, show_install: bool) -> None:
|
|
702
|
+
"""
|
|
703
|
+
Generate shell completion script.
|
|
704
|
+
|
|
705
|
+
Outputs a completion script for the specified shell that can be
|
|
706
|
+
sourced or saved to the appropriate location.
|
|
707
|
+
|
|
708
|
+
Examples:
|
|
709
|
+
# Bash: Add to ~/.bashrc
|
|
710
|
+
eval "$(yuho completion bash)"
|
|
711
|
+
|
|
712
|
+
# Zsh: Add to ~/.zshrc
|
|
713
|
+
eval "$(yuho completion zsh)"
|
|
714
|
+
|
|
715
|
+
# Fish: Save to completions directory
|
|
716
|
+
yuho completion fish > ~/.config/fish/completions/yuho.fish
|
|
717
|
+
|
|
718
|
+
Use --install to see detailed installation instructions.
|
|
719
|
+
"""
|
|
720
|
+
from yuho.cli.completions import get_completion_script, get_install_instructions
|
|
721
|
+
|
|
722
|
+
shell_lower = shell.lower()
|
|
723
|
+
|
|
724
|
+
if show_install:
|
|
725
|
+
click.echo(get_install_instructions(shell_lower))
|
|
726
|
+
else:
|
|
727
|
+
click.echo(get_completion_script(shell_lower))
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
# =============================================================================
|
|
731
|
+
# Config command
|
|
732
|
+
# =============================================================================
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
@cli.group()
|
|
736
|
+
@click.pass_context
|
|
737
|
+
def config(ctx: click.Context) -> None:
|
|
738
|
+
"""
|
|
739
|
+
Manage Yuho configuration.
|
|
740
|
+
|
|
741
|
+
View and modify configuration settings for all Yuho components.
|
|
742
|
+
"""
|
|
743
|
+
pass
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
@config.command("show")
|
|
747
|
+
@click.option("-s", "--section", type=click.Choice(["llm", "transpile", "lsp", "mcp"]),
|
|
748
|
+
help="Show only specific section")
|
|
749
|
+
@click.option("-f", "--format", "fmt", type=click.Choice(["toml", "json"]),
|
|
750
|
+
default="toml", help="Output format")
|
|
751
|
+
@click.pass_context
|
|
752
|
+
def config_show(ctx: click.Context, section: Optional[str], fmt: str) -> None:
|
|
753
|
+
"""
|
|
754
|
+
Display current configuration.
|
|
755
|
+
|
|
756
|
+
Shows all configuration values from file and environment.
|
|
757
|
+
|
|
758
|
+
Examples:
|
|
759
|
+
yuho config show
|
|
760
|
+
yuho config show -s llm
|
|
761
|
+
yuho config show -f json
|
|
762
|
+
"""
|
|
763
|
+
from yuho.cli.commands.config import run_config_show
|
|
764
|
+
run_config_show(section=section, format=fmt, verbose=ctx.obj["verbose"])
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
@config.command("set")
|
|
768
|
+
@click.argument("key")
|
|
769
|
+
@click.argument("value")
|
|
770
|
+
@click.pass_context
|
|
771
|
+
def config_set(ctx: click.Context, key: str, value: str) -> None:
|
|
772
|
+
"""
|
|
773
|
+
Set a configuration value.
|
|
774
|
+
|
|
775
|
+
KEY must be in format 'section.key' (e.g., 'llm.provider').
|
|
776
|
+
|
|
777
|
+
Examples:
|
|
778
|
+
yuho config set llm.provider ollama
|
|
779
|
+
yuho config set llm.model llama3
|
|
780
|
+
yuho config set mcp.port 9000
|
|
781
|
+
"""
|
|
782
|
+
from yuho.cli.commands.config import run_config_set
|
|
783
|
+
run_config_set(key, value, verbose=ctx.obj["verbose"])
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
@config.command("init")
|
|
787
|
+
@click.option("--force", is_flag=True, help="Overwrite existing config file")
|
|
788
|
+
@click.pass_context
|
|
789
|
+
def config_init(ctx: click.Context, force: bool) -> None:
|
|
790
|
+
"""
|
|
791
|
+
Create a default configuration file.
|
|
792
|
+
|
|
793
|
+
Creates ~/.config/yuho/config.toml with sensible defaults.
|
|
794
|
+
"""
|
|
795
|
+
from yuho.cli.commands.config import run_config_init
|
|
796
|
+
run_config_init(force=force, verbose=ctx.obj["verbose"])
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
# =============================================================================
|
|
800
|
+
# Library command
|
|
801
|
+
# =============================================================================
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
@cli.group()
|
|
805
|
+
@click.pass_context
|
|
806
|
+
def library(ctx: click.Context) -> None:
|
|
807
|
+
"""
|
|
808
|
+
Manage Yuho statute packages.
|
|
809
|
+
|
|
810
|
+
Search, install, update, and manage statute packages from the library.
|
|
811
|
+
"""
|
|
812
|
+
pass
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
@library.command("search")
|
|
816
|
+
@click.argument("query")
|
|
817
|
+
@click.option("-j", "--jurisdiction", help="Filter by jurisdiction")
|
|
818
|
+
@click.option("-t", "--tag", "tags", multiple=True, help="Filter by tag")
|
|
819
|
+
@click.option("-n", "--limit", type=int, default=20, help="Max results")
|
|
820
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
821
|
+
@click.pass_context
|
|
822
|
+
def library_search(
|
|
823
|
+
ctx: click.Context,
|
|
824
|
+
query: str,
|
|
825
|
+
jurisdiction: Optional[str],
|
|
826
|
+
tags: tuple,
|
|
827
|
+
limit: int,
|
|
828
|
+
json_output: bool,
|
|
829
|
+
) -> None:
|
|
830
|
+
"""
|
|
831
|
+
Search for packages in the library.
|
|
832
|
+
|
|
833
|
+
Examples:
|
|
834
|
+
yuho library search theft
|
|
835
|
+
yuho library search S403 --jurisdiction singapore
|
|
836
|
+
"""
|
|
837
|
+
from yuho.cli.commands.library import run_library_search
|
|
838
|
+
run_library_search(
|
|
839
|
+
query,
|
|
840
|
+
jurisdiction=jurisdiction,
|
|
841
|
+
tags=list(tags) if tags else None,
|
|
842
|
+
limit=limit,
|
|
843
|
+
json_output=json_output,
|
|
844
|
+
verbose=ctx.obj["verbose"],
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
@library.command("install")
|
|
849
|
+
@click.argument("package")
|
|
850
|
+
@click.option("-f", "--force", is_flag=True, help="Overwrite existing")
|
|
851
|
+
@click.option("--no-deps", is_flag=True, help="Skip dependencies")
|
|
852
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
853
|
+
@click.pass_context
|
|
854
|
+
def library_install(
|
|
855
|
+
ctx: click.Context,
|
|
856
|
+
package: str,
|
|
857
|
+
force: bool,
|
|
858
|
+
no_deps: bool,
|
|
859
|
+
json_output: bool,
|
|
860
|
+
) -> None:
|
|
861
|
+
"""
|
|
862
|
+
Install a package from registry or local path.
|
|
863
|
+
|
|
864
|
+
Examples:
|
|
865
|
+
yuho library install S403
|
|
866
|
+
yuho library install ./my-statute.yhpkg
|
|
867
|
+
"""
|
|
868
|
+
from yuho.cli.commands.library import run_library_install
|
|
869
|
+
run_library_install(
|
|
870
|
+
package,
|
|
871
|
+
force=force,
|
|
872
|
+
no_deps=no_deps,
|
|
873
|
+
json_output=json_output,
|
|
874
|
+
verbose=ctx.obj["verbose"],
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
@library.command("uninstall")
|
|
879
|
+
@click.argument("package")
|
|
880
|
+
@click.option("--dry-run", is_flag=True, help="Show what would be uninstalled without doing it")
|
|
881
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
882
|
+
@click.pass_context
|
|
883
|
+
def library_uninstall(
|
|
884
|
+
ctx: click.Context,
|
|
885
|
+
package: str,
|
|
886
|
+
dry_run: bool,
|
|
887
|
+
json_output: bool,
|
|
888
|
+
) -> None:
|
|
889
|
+
"""
|
|
890
|
+
Uninstall an installed package.
|
|
891
|
+
|
|
892
|
+
Examples:
|
|
893
|
+
yuho library uninstall S403
|
|
894
|
+
yuho library uninstall S403 --dry-run
|
|
895
|
+
"""
|
|
896
|
+
from yuho.cli.commands.library import run_library_uninstall
|
|
897
|
+
run_library_uninstall(
|
|
898
|
+
package,
|
|
899
|
+
dry_run=dry_run,
|
|
900
|
+
json_output=json_output,
|
|
901
|
+
verbose=ctx.obj["verbose"],
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
@library.command("list")
|
|
906
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
907
|
+
@click.pass_context
|
|
908
|
+
def library_list(ctx: click.Context, json_output: bool) -> None:
|
|
909
|
+
"""
|
|
910
|
+
List all installed packages.
|
|
911
|
+
"""
|
|
912
|
+
from yuho.cli.commands.library import run_library_list
|
|
913
|
+
run_library_list(json_output=json_output, verbose=ctx.obj["verbose"])
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
@library.command("update")
|
|
917
|
+
@click.argument("package", required=False)
|
|
918
|
+
@click.option("--all", "all_packages", is_flag=True, help="Update all packages")
|
|
919
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
920
|
+
@click.pass_context
|
|
921
|
+
def library_update(
|
|
922
|
+
ctx: click.Context,
|
|
923
|
+
package: Optional[str],
|
|
924
|
+
all_packages: bool,
|
|
925
|
+
json_output: bool,
|
|
926
|
+
) -> None:
|
|
927
|
+
"""
|
|
928
|
+
Update one or all packages.
|
|
929
|
+
|
|
930
|
+
Without arguments, shows available updates.
|
|
931
|
+
Use --all to apply all updates.
|
|
932
|
+
|
|
933
|
+
Examples:
|
|
934
|
+
yuho library update # Show updates
|
|
935
|
+
yuho library update --all # Apply all updates
|
|
936
|
+
yuho library update S403 # Update specific package
|
|
937
|
+
"""
|
|
938
|
+
from yuho.cli.commands.library import run_library_update
|
|
939
|
+
run_library_update(
|
|
940
|
+
package,
|
|
941
|
+
all_packages=all_packages,
|
|
942
|
+
json_output=json_output,
|
|
943
|
+
verbose=ctx.obj["verbose"],
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
@library.command("publish")
|
|
948
|
+
@click.argument("path", type=click.Path(exists=True))
|
|
949
|
+
@click.option("--registry", help="Registry URL")
|
|
950
|
+
@click.option("--token", help="Auth token")
|
|
951
|
+
@click.option("--dry-run", is_flag=True, help="Validate package without publishing")
|
|
952
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
953
|
+
@click.pass_context
|
|
954
|
+
def library_publish(
|
|
955
|
+
ctx: click.Context,
|
|
956
|
+
path: str,
|
|
957
|
+
registry: Optional[str],
|
|
958
|
+
token: Optional[str],
|
|
959
|
+
dry_run: bool,
|
|
960
|
+
json_output: bool,
|
|
961
|
+
) -> None:
|
|
962
|
+
"""
|
|
963
|
+
Publish a package to the registry.
|
|
964
|
+
|
|
965
|
+
Examples:
|
|
966
|
+
yuho library publish ./my-statute --token $YUHO_TOKEN
|
|
967
|
+
yuho library publish ./my-statute --dry-run
|
|
968
|
+
"""
|
|
969
|
+
from yuho.cli.commands.library import run_library_publish
|
|
970
|
+
run_library_publish(
|
|
971
|
+
path,
|
|
972
|
+
registry=registry,
|
|
973
|
+
token=token,
|
|
974
|
+
dry_run=dry_run,
|
|
975
|
+
json_output=json_output,
|
|
976
|
+
verbose=ctx.obj["verbose"],
|
|
977
|
+
)
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
@library.command("info")
|
|
981
|
+
@click.argument("package")
|
|
982
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
983
|
+
@click.pass_context
|
|
984
|
+
def library_info(
|
|
985
|
+
ctx: click.Context,
|
|
986
|
+
package: str,
|
|
987
|
+
json_output: bool,
|
|
988
|
+
) -> None:
|
|
989
|
+
"""
|
|
990
|
+
Show detailed package information.
|
|
991
|
+
|
|
992
|
+
Examples:
|
|
993
|
+
yuho library info S403
|
|
994
|
+
"""
|
|
995
|
+
from yuho.cli.commands.library import run_library_info
|
|
996
|
+
run_library_info(
|
|
997
|
+
package,
|
|
998
|
+
json_output=json_output,
|
|
999
|
+
verbose=ctx.obj["verbose"],
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
@library.command("outdated")
|
|
1004
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
1005
|
+
@click.pass_context
|
|
1006
|
+
def library_outdated(
|
|
1007
|
+
ctx: click.Context,
|
|
1008
|
+
json_output: bool,
|
|
1009
|
+
) -> None:
|
|
1010
|
+
"""
|
|
1011
|
+
Show packages with updates available.
|
|
1012
|
+
|
|
1013
|
+
Displays installed packages that have newer versions in the registry,
|
|
1014
|
+
along with the type of update (major, minor, patch) and deprecation warnings.
|
|
1015
|
+
|
|
1016
|
+
Examples:
|
|
1017
|
+
yuho library outdated
|
|
1018
|
+
yuho library outdated --json
|
|
1019
|
+
"""
|
|
1020
|
+
from yuho.cli.commands.library import run_library_outdated
|
|
1021
|
+
run_library_outdated(
|
|
1022
|
+
json_output=json_output,
|
|
1023
|
+
verbose=ctx.obj["verbose"],
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
@library.command("tree")
|
|
1028
|
+
@click.argument("package", required=False)
|
|
1029
|
+
@click.option("--depth", "-d", default=10, help="Maximum depth to display")
|
|
1030
|
+
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
|
|
1031
|
+
@click.pass_context
|
|
1032
|
+
def library_tree(
|
|
1033
|
+
ctx: click.Context,
|
|
1034
|
+
package: Optional[str],
|
|
1035
|
+
depth: int,
|
|
1036
|
+
json_output: bool,
|
|
1037
|
+
) -> None:
|
|
1038
|
+
"""
|
|
1039
|
+
Show dependency tree for packages.
|
|
1040
|
+
|
|
1041
|
+
Displays a tree visualization of package dependencies. If no package
|
|
1042
|
+
is specified, shows trees for all installed packages.
|
|
1043
|
+
|
|
1044
|
+
Examples:
|
|
1045
|
+
yuho library tree
|
|
1046
|
+
yuho library tree S403
|
|
1047
|
+
yuho library tree --depth 3
|
|
1048
|
+
"""
|
|
1049
|
+
from yuho.cli.commands.library import run_library_tree
|
|
1050
|
+
run_library_tree(
|
|
1051
|
+
package=package,
|
|
1052
|
+
depth=depth,
|
|
1053
|
+
json_output=json_output,
|
|
1054
|
+
verbose=ctx.obj["verbose"],
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
def main() -> None:
|
|
1059
|
+
"""Main entry point."""
|
|
1060
|
+
cli()
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
if __name__ == "__main__":
|
|
1064
|
+
main()
|