ostruct-cli 0.4.0__py3-none-any.whl → 0.6.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.
- ostruct/cli/base_errors.py +183 -0
- ostruct/cli/cli.py +879 -592
- ostruct/cli/click_options.py +320 -202
- ostruct/cli/errors.py +273 -134
- ostruct/cli/exit_codes.py +18 -0
- ostruct/cli/file_info.py +30 -14
- ostruct/cli/file_list.py +4 -10
- ostruct/cli/file_utils.py +43 -35
- ostruct/cli/path_utils.py +32 -4
- ostruct/cli/schema_validation.py +213 -0
- ostruct/cli/security/allowed_checker.py +8 -0
- ostruct/cli/security/base.py +46 -0
- ostruct/cli/security/errors.py +83 -103
- ostruct/cli/security/security_manager.py +22 -9
- ostruct/cli/serialization.py +25 -0
- ostruct/cli/template_filters.py +5 -3
- ostruct/cli/template_rendering.py +46 -22
- ostruct/cli/template_utils.py +12 -4
- ostruct/cli/template_validation.py +26 -8
- ostruct/cli/token_utils.py +43 -0
- ostruct/cli/validators.py +109 -0
- ostruct_cli-0.6.0.dist-info/METADATA +404 -0
- ostruct_cli-0.6.0.dist-info/RECORD +43 -0
- {ostruct_cli-0.4.0.dist-info → ostruct_cli-0.6.0.dist-info}/WHEEL +1 -1
- ostruct_cli-0.4.0.dist-info/METADATA +0 -186
- ostruct_cli-0.4.0.dist-info/RECORD +0 -36
- {ostruct_cli-0.4.0.dist-info → ostruct_cli-0.6.0.dist-info}/LICENSE +0 -0
- {ostruct_cli-0.4.0.dist-info → ostruct_cli-0.6.0.dist-info}/entry_points.txt +0 -0
ostruct/cli/click_options.py
CHANGED
@@ -9,160 +9,349 @@ from typing import Any, Callable, TypeVar, Union, cast
|
|
9
9
|
|
10
10
|
import click
|
11
11
|
from click import Command
|
12
|
+
from typing_extensions import ParamSpec
|
12
13
|
|
13
14
|
from ostruct import __version__
|
14
15
|
from ostruct.cli.errors import ( # noqa: F401 - Used in error handling
|
15
16
|
SystemPromptError,
|
16
17
|
TaskTemplateVariableError,
|
17
18
|
)
|
19
|
+
from ostruct.cli.validators import (
|
20
|
+
validate_json_variable,
|
21
|
+
validate_name_path_pair,
|
22
|
+
validate_variable,
|
23
|
+
)
|
18
24
|
|
25
|
+
P = ParamSpec("P")
|
26
|
+
R = TypeVar("R")
|
19
27
|
F = TypeVar("F", bound=Callable[..., Any])
|
28
|
+
CommandDecorator = Callable[[F], Command]
|
20
29
|
DecoratedCommand = Union[Command, Callable[..., Any]]
|
21
30
|
|
22
31
|
|
23
|
-
def
|
24
|
-
ctx: click.Context, param: click.Parameter, value: Any
|
25
|
-
) -> Any:
|
26
|
-
"""Validate task-related parameters."""
|
27
|
-
if not hasattr(ctx, "params"):
|
28
|
-
return value
|
29
|
-
|
30
|
-
# Check for conflicting task parameters
|
31
|
-
if (
|
32
|
-
param.name == "task_file"
|
33
|
-
and value is not None
|
34
|
-
and ctx.params.get("task") is not None
|
35
|
-
):
|
36
|
-
raise click.UsageError("Cannot specify both --task and --task-file")
|
37
|
-
elif (
|
38
|
-
param.name == "task"
|
39
|
-
and value is not None
|
40
|
-
and ctx.params.get("task_file") is not None
|
41
|
-
):
|
42
|
-
raise click.UsageError("Cannot specify both --task and --task-file")
|
43
|
-
|
44
|
-
return value
|
45
|
-
|
46
|
-
|
47
|
-
def validate_system_prompt_params(
|
48
|
-
ctx: click.Context, param: click.Parameter, value: Any
|
49
|
-
) -> Any:
|
50
|
-
"""Validate system prompt parameters."""
|
51
|
-
if not hasattr(ctx, "params"):
|
52
|
-
return value
|
53
|
-
|
54
|
-
# Check for conflicting system prompt parameters
|
55
|
-
if (
|
56
|
-
param.name == "system_prompt_file"
|
57
|
-
and value is not None
|
58
|
-
and ctx.params.get("system_prompt") is not None
|
59
|
-
):
|
60
|
-
raise click.UsageError(
|
61
|
-
"Cannot specify both --system-prompt and --system-prompt-file"
|
62
|
-
)
|
63
|
-
elif (
|
64
|
-
param.name == "system_prompt"
|
65
|
-
and value is not None
|
66
|
-
and ctx.params.get("system_prompt_file") is not None
|
67
|
-
):
|
68
|
-
raise click.UsageError(
|
69
|
-
"Cannot specify both --system-prompt and --system-prompt-file"
|
70
|
-
)
|
71
|
-
|
72
|
-
return value
|
73
|
-
|
74
|
-
|
75
|
-
def debug_options(f: Callable) -> Callable:
|
32
|
+
def debug_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
76
33
|
"""Add debug-related CLI options."""
|
77
|
-
|
34
|
+
# Initial conversion to Command if needed
|
35
|
+
cmd: Any = f if isinstance(f, Command) else f
|
36
|
+
|
37
|
+
# Add options without redundant casts
|
38
|
+
cmd = click.option(
|
78
39
|
"--show-model-schema",
|
79
40
|
is_flag=True,
|
80
41
|
help="Show generated Pydantic model schema",
|
81
|
-
)(
|
82
|
-
|
42
|
+
)(cmd)
|
43
|
+
|
44
|
+
cmd = click.option(
|
83
45
|
"--debug-validation",
|
84
46
|
is_flag=True,
|
85
47
|
help="Show detailed validation errors",
|
86
|
-
)(
|
87
|
-
return f
|
48
|
+
)(cmd)
|
88
49
|
|
50
|
+
# Final cast to Command for return type
|
51
|
+
return cast(Command, cmd)
|
89
52
|
|
90
|
-
|
53
|
+
|
54
|
+
def file_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
91
55
|
"""Add file-related CLI options."""
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
"--
|
56
|
+
cmd: Any = f if isinstance(f, Command) else f
|
57
|
+
|
58
|
+
cmd = click.option(
|
59
|
+
"-f",
|
60
|
+
"--file",
|
61
|
+
"files",
|
97
62
|
multiple=True,
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
"
|
102
|
-
|
103
|
-
|
104
|
-
|
63
|
+
nargs=2,
|
64
|
+
metavar="<NAME> <PATH>",
|
65
|
+
callback=validate_name_path_pair,
|
66
|
+
help="""Associate a file with a variable name. The file will be available in
|
67
|
+
your template as the specified variable. You can specify this option multiple times.
|
68
|
+
Example: -f code main.py -f test test_main.py""",
|
69
|
+
shell_complete=click.Path(exists=True, file_okay=True, dir_okay=False),
|
70
|
+
)(cmd)
|
71
|
+
|
72
|
+
cmd = click.option(
|
73
|
+
"-d",
|
74
|
+
"--dir",
|
75
|
+
"dir",
|
76
|
+
multiple=True,
|
77
|
+
nargs=2,
|
78
|
+
metavar="<NAME> <DIR>",
|
79
|
+
callback=validate_name_path_pair,
|
80
|
+
help="""Associate a directory with a variable name. All files in the directory
|
81
|
+
will be available in your template. Use -R for recursive scanning.
|
82
|
+
Example: -d src ./src""",
|
83
|
+
shell_complete=click.Path(exists=True, file_okay=False, dir_okay=True),
|
84
|
+
)(cmd)
|
85
|
+
|
86
|
+
cmd = click.option(
|
87
|
+
"-p",
|
88
|
+
"--pattern",
|
89
|
+
"patterns",
|
90
|
+
multiple=True,
|
91
|
+
nargs=2,
|
92
|
+
metavar="<NAME> <PATTERN>",
|
93
|
+
help="""Associate a glob pattern with a variable name. Matching files will be
|
94
|
+
available in your template. Use -R for recursive matching.
|
95
|
+
Example: -p logs '*.log'""",
|
96
|
+
)(cmd)
|
97
|
+
|
98
|
+
cmd = click.option(
|
99
|
+
"-R",
|
100
|
+
"--recursive",
|
101
|
+
is_flag=True,
|
102
|
+
help="Process directories and patterns recursively",
|
103
|
+
)(cmd)
|
104
|
+
|
105
|
+
cmd = click.option(
|
106
|
+
"--base-dir",
|
107
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
108
|
+
help="""Base directory for resolving relative paths. All file operations will be
|
109
|
+
relative to this directory. Defaults to current directory.""",
|
110
|
+
shell_complete=click.Path(exists=True, file_okay=False, dir_okay=True),
|
111
|
+
)(cmd)
|
112
|
+
|
113
|
+
cmd = click.option(
|
114
|
+
"-A",
|
115
|
+
"--allow",
|
116
|
+
"allowed_dirs",
|
105
117
|
multiple=True,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
)(
|
111
|
-
|
118
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
119
|
+
help="""Add an allowed directory for security. Files must be within allowed
|
120
|
+
directories. Can be specified multiple times.""",
|
121
|
+
shell_complete=click.Path(exists=True, file_okay=False, dir_okay=True),
|
122
|
+
)(cmd)
|
123
|
+
|
124
|
+
cmd = click.option(
|
112
125
|
"--allowed-dir-file",
|
113
|
-
type=
|
114
|
-
help="File containing allowed directory paths
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
def variable_options(f: Callable) -> Callable:
|
126
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False),
|
127
|
+
help="""File containing allowed directory paths, one per line. Lines starting
|
128
|
+
with # are treated as comments.""",
|
129
|
+
shell_complete=click.Path(exists=True, file_okay=True, dir_okay=False),
|
130
|
+
)(cmd)
|
131
|
+
|
132
|
+
return cast(Command, cmd)
|
133
|
+
|
134
|
+
|
135
|
+
def variable_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
126
136
|
"""Add variable-related CLI options."""
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
137
|
+
cmd: Any = f if isinstance(f, Command) else f
|
138
|
+
|
139
|
+
cmd = click.option(
|
140
|
+
"-V",
|
141
|
+
"--var",
|
142
|
+
"var",
|
143
|
+
multiple=True,
|
144
|
+
metavar="name=value",
|
145
|
+
callback=validate_variable,
|
146
|
+
help="""Define a simple string variable. Format: name=value
|
147
|
+
Example: -V debug=true -V env=prod""",
|
148
|
+
)(cmd)
|
149
|
+
|
150
|
+
cmd = click.option(
|
151
|
+
"-J",
|
131
152
|
"--json-var",
|
132
|
-
"
|
153
|
+
"json_var",
|
133
154
|
multiple=True,
|
134
|
-
|
135
|
-
|
136
|
-
|
155
|
+
metavar='name=\'{"json":"value"}\'',
|
156
|
+
callback=validate_json_variable,
|
157
|
+
help="""Define a JSON variable. Format: name='{"key":"value"}'
|
158
|
+
Example: -J config='{"env":"prod","debug":true}'""",
|
159
|
+
)(cmd)
|
137
160
|
|
161
|
+
return cast(Command, cmd)
|
138
162
|
|
139
|
-
|
163
|
+
|
164
|
+
def model_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
140
165
|
"""Add model-related CLI options."""
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
"--
|
146
|
-
|
147
|
-
|
148
|
-
"
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
166
|
+
cmd: Any = f if isinstance(f, Command) else f
|
167
|
+
|
168
|
+
cmd = click.option(
|
169
|
+
"-m",
|
170
|
+
"--model",
|
171
|
+
default="gpt-4o",
|
172
|
+
show_default=True,
|
173
|
+
help="""OpenAI model to use. Must support structured output.
|
174
|
+
Supported models:
|
175
|
+
- gpt-4o (128k context window)
|
176
|
+
- o1 (200k context window)
|
177
|
+
- o3-mini (200k context window)""",
|
178
|
+
)(cmd)
|
179
|
+
|
180
|
+
cmd = click.option(
|
181
|
+
"--temperature",
|
182
|
+
type=click.FloatRange(0.0, 2.0),
|
183
|
+
help="""Sampling temperature. Controls randomness in the output.
|
184
|
+
Range: 0.0 to 2.0. Lower values are more focused.""",
|
185
|
+
)(cmd)
|
186
|
+
|
187
|
+
cmd = click.option(
|
188
|
+
"--max-output-tokens",
|
189
|
+
type=click.IntRange(1, None),
|
190
|
+
help="""Maximum number of tokens in the output.
|
191
|
+
Higher values allow longer responses but cost more.""",
|
192
|
+
)(cmd)
|
193
|
+
|
194
|
+
cmd = click.option(
|
195
|
+
"--top-p",
|
196
|
+
type=click.FloatRange(0.0, 1.0),
|
197
|
+
help="""Top-p (nucleus) sampling parameter. Controls diversity.
|
198
|
+
Range: 0.0 to 1.0. Lower values are more focused.""",
|
199
|
+
)(cmd)
|
200
|
+
|
201
|
+
cmd = click.option(
|
154
202
|
"--frequency-penalty",
|
155
|
-
type=
|
156
|
-
|
157
|
-
|
158
|
-
)(
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
203
|
+
type=click.FloatRange(-2.0, 2.0),
|
204
|
+
help="""Frequency penalty for text generation.
|
205
|
+
Range: -2.0 to 2.0. Positive values reduce repetition.""",
|
206
|
+
)(cmd)
|
207
|
+
|
208
|
+
cmd = click.option(
|
209
|
+
"--presence-penalty",
|
210
|
+
type=click.FloatRange(-2.0, 2.0),
|
211
|
+
help="""Presence penalty for text generation.
|
212
|
+
Range: -2.0 to 2.0. Positive values encourage new topics.""",
|
213
|
+
)(cmd)
|
214
|
+
|
215
|
+
cmd = click.option(
|
216
|
+
"--reasoning-effort",
|
217
|
+
type=click.Choice(["low", "medium", "high"]),
|
218
|
+
help="""Control reasoning effort (if supported by model).
|
219
|
+
Higher values may improve output quality but take longer.""",
|
220
|
+
)(cmd)
|
221
|
+
|
222
|
+
return cast(Command, cmd)
|
223
|
+
|
224
|
+
|
225
|
+
def system_prompt_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
226
|
+
"""Add system prompt related CLI options."""
|
227
|
+
cmd: Any = f if isinstance(f, Command) else f
|
228
|
+
|
229
|
+
cmd = click.option(
|
230
|
+
"--sys-prompt",
|
231
|
+
"system_prompt",
|
232
|
+
help="""Provide system prompt directly. This sets the initial context
|
233
|
+
for the model. Example: --sys-prompt "You are a code reviewer." """,
|
234
|
+
)(cmd)
|
235
|
+
|
236
|
+
cmd = click.option(
|
237
|
+
"--sys-file",
|
238
|
+
"system_prompt_file",
|
239
|
+
type=click.Path(exists=True, dir_okay=False),
|
240
|
+
help="""Load system prompt from file. The file should contain the prompt text.
|
241
|
+
Example: --sys-file prompts/code_review.txt""",
|
242
|
+
shell_complete=click.Path(exists=True, file_okay=True, dir_okay=False),
|
243
|
+
)(cmd)
|
244
|
+
|
245
|
+
cmd = click.option(
|
246
|
+
"--ignore-task-sysprompt",
|
247
|
+
is_flag=True,
|
248
|
+
help="""Ignore system prompt in task template. By default, system prompts
|
249
|
+
in template frontmatter are used.""",
|
250
|
+
)(cmd)
|
251
|
+
|
252
|
+
return cast(Command, cmd)
|
253
|
+
|
254
|
+
|
255
|
+
def output_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
256
|
+
"""Add output-related CLI options."""
|
257
|
+
cmd: Any = f if isinstance(f, Command) else f
|
258
|
+
|
259
|
+
cmd = click.option(
|
260
|
+
"--output-file",
|
261
|
+
type=click.Path(dir_okay=False),
|
262
|
+
help="""Write output to file instead of stdout.
|
263
|
+
Example: --output-file result.json""",
|
264
|
+
shell_complete=click.Path(file_okay=True, dir_okay=False),
|
265
|
+
)(cmd)
|
163
266
|
|
267
|
+
cmd = click.option(
|
268
|
+
"--dry-run",
|
269
|
+
is_flag=True,
|
270
|
+
help="""Validate and render but skip API call. Useful for testing
|
271
|
+
template rendering and validation.""",
|
272
|
+
)(cmd)
|
273
|
+
|
274
|
+
return cast(Command, cmd)
|
275
|
+
|
276
|
+
|
277
|
+
def api_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
278
|
+
"""Add API-related CLI options."""
|
279
|
+
cmd: Any = f if isinstance(f, Command) else f
|
280
|
+
|
281
|
+
cmd = click.option(
|
282
|
+
"--api-key",
|
283
|
+
help="""OpenAI API key. If not provided, uses OPENAI_API_KEY
|
284
|
+
environment variable.""",
|
285
|
+
)(cmd)
|
286
|
+
|
287
|
+
cmd = click.option(
|
288
|
+
"--timeout",
|
289
|
+
type=click.FloatRange(1.0, None),
|
290
|
+
default=60.0,
|
291
|
+
show_default=True,
|
292
|
+
help="API timeout in seconds.",
|
293
|
+
)(cmd)
|
294
|
+
|
295
|
+
return cast(Command, cmd)
|
296
|
+
|
297
|
+
|
298
|
+
def debug_progress_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
299
|
+
"""Add debugging and progress CLI options."""
|
300
|
+
cmd: Any = f if isinstance(f, Command) else f
|
301
|
+
|
302
|
+
cmd = click.option(
|
303
|
+
"--no-progress", is_flag=True, help="Disable progress indicators"
|
304
|
+
)(cmd)
|
164
305
|
|
165
|
-
|
306
|
+
cmd = click.option(
|
307
|
+
"--progress-level",
|
308
|
+
type=click.Choice(["none", "basic", "detailed"]),
|
309
|
+
default="basic",
|
310
|
+
show_default=True,
|
311
|
+
help="""Control progress verbosity. 'none' shows no progress,
|
312
|
+
'basic' shows key steps, 'detailed' shows all steps.""",
|
313
|
+
)(cmd)
|
314
|
+
|
315
|
+
cmd = click.option(
|
316
|
+
"--verbose", is_flag=True, help="Enable verbose logging"
|
317
|
+
)(cmd)
|
318
|
+
|
319
|
+
cmd = click.option(
|
320
|
+
"--debug-openai-stream",
|
321
|
+
is_flag=True,
|
322
|
+
help="Debug OpenAI streaming process",
|
323
|
+
)(cmd)
|
324
|
+
|
325
|
+
return cast(Command, cmd)
|
326
|
+
|
327
|
+
|
328
|
+
def all_options(f: Union[Command, Callable[..., Any]]) -> Command:
|
329
|
+
"""Add all CLI options.
|
330
|
+
|
331
|
+
Args:
|
332
|
+
f: Function to decorate
|
333
|
+
|
334
|
+
Returns:
|
335
|
+
Decorated function
|
336
|
+
"""
|
337
|
+
decorators = [
|
338
|
+
model_options, # Model selection and parameters first
|
339
|
+
system_prompt_options, # System prompt configuration
|
340
|
+
file_options, # File and directory handling
|
341
|
+
variable_options, # Variable definitions
|
342
|
+
output_options, # Output control
|
343
|
+
api_options, # API configuration
|
344
|
+
debug_options, # Debug settings
|
345
|
+
debug_progress_options, # Progress and logging
|
346
|
+
]
|
347
|
+
|
348
|
+
for decorator in decorators:
|
349
|
+
f = decorator(f)
|
350
|
+
|
351
|
+
return cast(Command, f)
|
352
|
+
|
353
|
+
|
354
|
+
def create_click_command() -> CommandDecorator:
|
166
355
|
"""Create the Click command with all options.
|
167
356
|
|
168
357
|
Returns:
|
@@ -170,88 +359,17 @@ def create_click_command() -> Callable[[F], Command]:
|
|
170
359
|
"""
|
171
360
|
|
172
361
|
def decorator(f: F) -> Command:
|
173
|
-
#
|
174
|
-
cmd:
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
"
|
181
|
-
|
182
|
-
type=str,
|
183
|
-
callback=validate_task_params,
|
184
|
-
)(cmd)
|
185
|
-
cmd = click.option(
|
186
|
-
"--task-file",
|
187
|
-
help="Task template file path",
|
188
|
-
type=str,
|
189
|
-
callback=validate_task_params,
|
190
|
-
)(cmd)
|
191
|
-
cmd = click.option(
|
192
|
-
"--system-prompt",
|
193
|
-
help="System prompt string",
|
194
|
-
type=str,
|
195
|
-
callback=validate_system_prompt_params,
|
196
|
-
)(cmd)
|
197
|
-
cmd = click.option(
|
198
|
-
"--system-prompt-file",
|
199
|
-
help="System prompt file path",
|
200
|
-
type=str,
|
201
|
-
callback=validate_system_prompt_params,
|
202
|
-
)(cmd)
|
203
|
-
cmd = click.option(
|
204
|
-
"--schema-file",
|
205
|
-
required=True,
|
206
|
-
help="JSON schema file for response validation",
|
207
|
-
type=str,
|
208
|
-
)(cmd)
|
209
|
-
cmd = click.option(
|
210
|
-
"--ignore-task-sysprompt",
|
211
|
-
is_flag=True,
|
212
|
-
help="Ignore system prompt from task template YAML frontmatter",
|
213
|
-
)(cmd)
|
214
|
-
cmd = click.option(
|
215
|
-
"--timeout",
|
216
|
-
type=float,
|
217
|
-
default=60.0,
|
218
|
-
help="API timeout in seconds",
|
219
|
-
)(cmd)
|
220
|
-
cmd = click.option(
|
221
|
-
"--output-file", help="Write JSON output to file", type=str
|
222
|
-
)(cmd)
|
223
|
-
cmd = click.option(
|
224
|
-
"--dry-run",
|
225
|
-
is_flag=True,
|
226
|
-
help="Simulate API call without making request",
|
227
|
-
)(cmd)
|
228
|
-
cmd = click.option(
|
229
|
-
"--no-progress", is_flag=True, help="Disable progress indicators"
|
230
|
-
)(cmd)
|
231
|
-
cmd = click.option(
|
232
|
-
"--progress-level",
|
233
|
-
type=click.Choice(["none", "basic", "detailed"]),
|
234
|
-
default="basic",
|
235
|
-
help="Progress reporting level",
|
236
|
-
)(cmd)
|
237
|
-
cmd = click.option(
|
238
|
-
"--api-key", help="OpenAI API key (overrides env var)", type=str
|
239
|
-
)(cmd)
|
240
|
-
cmd = click.option(
|
241
|
-
"--verbose",
|
242
|
-
is_flag=True,
|
243
|
-
help="Enable verbose output and detailed logging",
|
244
|
-
)(cmd)
|
245
|
-
cmd = click.option(
|
246
|
-
"--debug-openai-stream",
|
247
|
-
is_flag=True,
|
248
|
-
help="Enable low-level debug output for OpenAI streaming",
|
362
|
+
# Initial command creation
|
363
|
+
cmd: Any = click.command()(f)
|
364
|
+
|
365
|
+
# Add version option
|
366
|
+
cmd = click.version_option(
|
367
|
+
__version__,
|
368
|
+
"--version",
|
369
|
+
"-V",
|
370
|
+
message="%(prog)s CLI version %(version)s",
|
249
371
|
)(cmd)
|
250
|
-
|
251
|
-
cmd = file_options(cmd)
|
252
|
-
cmd = variable_options(cmd)
|
253
|
-
cmd = model_options(cmd)
|
254
|
-
cmd = click.version_option(version=__version__)(cmd)
|
372
|
+
|
255
373
|
return cast(Command, cmd)
|
256
374
|
|
257
375
|
return decorator
|