python-infrakit-dev 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.
- infrakit/__init__.py +0 -0
- infrakit/cli/__init__.py +1 -0
- infrakit/cli/commands/__init__.py +1 -0
- infrakit/cli/commands/deps.py +530 -0
- infrakit/cli/commands/init.py +129 -0
- infrakit/cli/commands/llm.py +295 -0
- infrakit/cli/commands/logger.py +160 -0
- infrakit/cli/commands/module.py +342 -0
- infrakit/cli/commands/time.py +81 -0
- infrakit/cli/main.py +65 -0
- infrakit/core/__init__.py +0 -0
- infrakit/core/config/__init__.py +0 -0
- infrakit/core/config/converter.py +480 -0
- infrakit/core/config/exporter.py +304 -0
- infrakit/core/config/loader.py +713 -0
- infrakit/core/config/validator.py +389 -0
- infrakit/core/logger/__init__.py +21 -0
- infrakit/core/logger/formatters.py +143 -0
- infrakit/core/logger/handlers.py +322 -0
- infrakit/core/logger/retention.py +176 -0
- infrakit/core/logger/setup.py +314 -0
- infrakit/deps/__init__.py +239 -0
- infrakit/deps/clean.py +141 -0
- infrakit/deps/depfile.py +405 -0
- infrakit/deps/health.py +357 -0
- infrakit/deps/optimizer.py +642 -0
- infrakit/deps/scanner.py +550 -0
- infrakit/llm/__init__.py +35 -0
- infrakit/llm/batch.py +165 -0
- infrakit/llm/client.py +575 -0
- infrakit/llm/key_manager.py +728 -0
- infrakit/llm/llm_readme.md +306 -0
- infrakit/llm/models.py +148 -0
- infrakit/llm/providers/__init__.py +5 -0
- infrakit/llm/providers/base.py +112 -0
- infrakit/llm/providers/gemini.py +164 -0
- infrakit/llm/providers/openai.py +168 -0
- infrakit/llm/rate_limiter.py +54 -0
- infrakit/scaffolder/__init__.py +31 -0
- infrakit/scaffolder/ai.py +508 -0
- infrakit/scaffolder/backend.py +555 -0
- infrakit/scaffolder/cli_tool.py +386 -0
- infrakit/scaffolder/generator.py +338 -0
- infrakit/scaffolder/pipeline.py +562 -0
- infrakit/scaffolder/registry.py +121 -0
- infrakit/time/__init__.py +60 -0
- infrakit/time/profiler.py +511 -0
- python_infrakit_dev-0.1.0.dist-info/METADATA +124 -0
- python_infrakit_dev-0.1.0.dist-info/RECORD +51 -0
- python_infrakit_dev-0.1.0.dist-info/WHEEL +4 -0
- python_infrakit_dev-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"""
|
|
2
|
+
infrakit.cli.commands.module
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
``infrakit module`` subcommand group.
|
|
5
|
+
|
|
6
|
+
Commands
|
|
7
|
+
--------
|
|
8
|
+
infrakit module create <path> [--no-init] [--no-init-parents]
|
|
9
|
+
infrakit module delete <path> [--no-confirm]
|
|
10
|
+
infrakit module tree [root] [--show-ignored]
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import fnmatch
|
|
16
|
+
import shutil
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
import typer
|
|
21
|
+
|
|
22
|
+
module_app = typer.Typer(
|
|
23
|
+
name="module",
|
|
24
|
+
help="Create, delete, or inspect module directories.",
|
|
25
|
+
no_args_is_help=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# ── helpers ───────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
def _abort(msg: str) -> None:
|
|
31
|
+
typer.echo(typer.style(f"✗ {msg}", fg=typer.colors.RED), err=True)
|
|
32
|
+
raise typer.Exit(1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _created(rel: Path) -> None:
|
|
36
|
+
typer.echo(f" {typer.style('+', fg=typer.colors.GREEN, bold=True)} {rel}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _skipped(rel: Path, reason: str = "already exists") -> None:
|
|
40
|
+
typer.echo(
|
|
41
|
+
f" {typer.style('~', fg=typer.colors.BRIGHT_BLACK)} "
|
|
42
|
+
f"{typer.style(str(rel), fg=typer.colors.BRIGHT_BLACK)}"
|
|
43
|
+
f" {typer.style(f'({reason})', fg=typer.colors.BRIGHT_BLACK)}"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _write_init(path: Path, cwd: Path) -> None:
|
|
48
|
+
rel = path.relative_to(cwd)
|
|
49
|
+
if path.exists():
|
|
50
|
+
_skipped(rel)
|
|
51
|
+
return
|
|
52
|
+
path.write_text('"""{}"""\n'.format(path.parent.name), encoding="utf-8")
|
|
53
|
+
_created(rel)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _make_dir(path: Path, cwd: Path) -> None:
|
|
57
|
+
rel = path.relative_to(cwd)
|
|
58
|
+
if path.exists():
|
|
59
|
+
_skipped(rel)
|
|
60
|
+
return
|
|
61
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
_created(rel)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ── gitignore parser ──────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
def _load_gitignore_patterns(root: Path) -> list[str]:
|
|
68
|
+
"""
|
|
69
|
+
Read .gitignore from root and return a list of raw patterns.
|
|
70
|
+
Always includes .git itself regardless of .gitignore contents.
|
|
71
|
+
"""
|
|
72
|
+
patterns: list[str] = [".git"]
|
|
73
|
+
gitignore = root / ".gitignore"
|
|
74
|
+
if not gitignore.exists():
|
|
75
|
+
return patterns
|
|
76
|
+
for line in gitignore.read_text(encoding="utf-8").splitlines():
|
|
77
|
+
line = line.strip()
|
|
78
|
+
if line and not line.startswith("#"):
|
|
79
|
+
patterns.append(line)
|
|
80
|
+
return patterns
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _is_ignored(path: Path, root: Path, patterns: list[str]) -> bool:
|
|
84
|
+
"""
|
|
85
|
+
Return True if ``path`` matches any gitignore pattern.
|
|
86
|
+
|
|
87
|
+
Handles:
|
|
88
|
+
- globstar prefix **/<name>/ — match bare name at any depth
|
|
89
|
+
- bare patterns __pycache__ — match any path component
|
|
90
|
+
- anchored patterns src/*.py — match against full relative path
|
|
91
|
+
- trailing slashes stripped (directory-only markers)
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
rel = path.relative_to(root).as_posix()
|
|
95
|
+
except ValueError:
|
|
96
|
+
rel = path.name
|
|
97
|
+
|
|
98
|
+
rel_parts = Path(rel).parts
|
|
99
|
+
|
|
100
|
+
for pattern in patterns:
|
|
101
|
+
# ── globstar: **/<name> or **/<name>/ → bare name at any depth ───────
|
|
102
|
+
if pattern.startswith("**/"):
|
|
103
|
+
bare = pattern[3:].rstrip("/")
|
|
104
|
+
if any(fnmatch.fnmatch(part, bare) for part in rel_parts):
|
|
105
|
+
return True
|
|
106
|
+
continue
|
|
107
|
+
|
|
108
|
+
p = pattern.rstrip("/")
|
|
109
|
+
|
|
110
|
+
# ── bare name (no slash) → match against every path component ────────
|
|
111
|
+
if "/" not in p:
|
|
112
|
+
if any(fnmatch.fnmatch(part, p) for part in rel_parts):
|
|
113
|
+
return True
|
|
114
|
+
else:
|
|
115
|
+
# ── anchored pattern (contains slash) → match full relative path ─
|
|
116
|
+
if fnmatch.fnmatch(rel, p):
|
|
117
|
+
return True
|
|
118
|
+
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ── tree renderer ─────────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
_PIPE = "│ "
|
|
125
|
+
_TEE = "├── "
|
|
126
|
+
_LAST = "└── "
|
|
127
|
+
_BLANK = " "
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _render_tree(
|
|
131
|
+
path: Path,
|
|
132
|
+
root: Path,
|
|
133
|
+
patterns: list[str],
|
|
134
|
+
show_ignored: bool,
|
|
135
|
+
prefix: str = "",
|
|
136
|
+
) -> tuple[int, int]:
|
|
137
|
+
"""
|
|
138
|
+
Recursively render the tree under ``path``.
|
|
139
|
+
Returns (dir_count, file_count).
|
|
140
|
+
"""
|
|
141
|
+
dirs = 0
|
|
142
|
+
files = 0
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
entries = sorted(path.iterdir(), key=lambda p: (p.is_file(), p.name.lower()))
|
|
146
|
+
except PermissionError:
|
|
147
|
+
return dirs, files
|
|
148
|
+
|
|
149
|
+
# filter ignored unless show_ignored
|
|
150
|
+
if not show_ignored:
|
|
151
|
+
entries = [e for e in entries if not _is_ignored(e, root, patterns)]
|
|
152
|
+
|
|
153
|
+
for i, entry in enumerate(entries):
|
|
154
|
+
is_last = i == len(entries) - 1
|
|
155
|
+
connector = _LAST if is_last else _TEE
|
|
156
|
+
extension = _BLANK if is_last else _PIPE
|
|
157
|
+
ignored = _is_ignored(entry, root, patterns)
|
|
158
|
+
|
|
159
|
+
if entry.is_dir():
|
|
160
|
+
dirs += 1
|
|
161
|
+
label = typer.style(entry.name + "/", fg=typer.colors.CYAN, bold=True)
|
|
162
|
+
dim = typer.style(" (ignored)", fg=typer.colors.BRIGHT_BLACK) if ignored else ""
|
|
163
|
+
typer.echo(f"{prefix}{connector}{label}{dim}")
|
|
164
|
+
d, f = _render_tree(entry, root, patterns, show_ignored, prefix + extension)
|
|
165
|
+
dirs += d
|
|
166
|
+
files += f
|
|
167
|
+
else:
|
|
168
|
+
files += 1
|
|
169
|
+
if ignored:
|
|
170
|
+
label = typer.style(entry.name, fg=typer.colors.BRIGHT_BLACK)
|
|
171
|
+
dim = typer.style(" (ignored)", fg=typer.colors.BRIGHT_BLACK)
|
|
172
|
+
else:
|
|
173
|
+
label = entry.name
|
|
174
|
+
dim = ""
|
|
175
|
+
typer.echo(f"{prefix}{connector}{label}{dim}")
|
|
176
|
+
|
|
177
|
+
return dirs, files
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# ── ik module create ──────────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
@module_app.command("create")
|
|
183
|
+
def cmd_create(
|
|
184
|
+
module_path: str = typer.Argument(
|
|
185
|
+
...,
|
|
186
|
+
help="Module path, supports nesting e.g. core/models or just utils.",
|
|
187
|
+
),
|
|
188
|
+
init: bool = typer.Option(
|
|
189
|
+
True, "--init/--no-init",
|
|
190
|
+
help="Add __init__.py to the final module directory (default: on).",
|
|
191
|
+
),
|
|
192
|
+
init_parents: bool = typer.Option(
|
|
193
|
+
True, "--init-parents/--no-init-parents",
|
|
194
|
+
help="Add __init__.py to intermediate parent directories (default: on).",
|
|
195
|
+
),
|
|
196
|
+
) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Create a module directory with optional __init__.py files.
|
|
199
|
+
|
|
200
|
+
Supports nested paths — intermediate directories are created automatically.
|
|
201
|
+
Any directory or file that already exists is left untouched.
|
|
202
|
+
|
|
203
|
+
\b
|
|
204
|
+
Examples
|
|
205
|
+
--------
|
|
206
|
+
ik module create utils
|
|
207
|
+
ik module create core/models
|
|
208
|
+
ik module create core/models --no-init-parents # skip __init__.py in core/
|
|
209
|
+
ik module create core/models --no-init # folder only, no __init__.py anywhere
|
|
210
|
+
"""
|
|
211
|
+
cwd = Path.cwd()
|
|
212
|
+
parts = Path(module_path).parts
|
|
213
|
+
|
|
214
|
+
if not parts:
|
|
215
|
+
_abort("Module path cannot be empty.")
|
|
216
|
+
|
|
217
|
+
typer.echo()
|
|
218
|
+
|
|
219
|
+
for i, _ in enumerate(parts):
|
|
220
|
+
current = cwd / Path(*parts[: i + 1])
|
|
221
|
+
is_leaf = i == len(parts) - 1
|
|
222
|
+
|
|
223
|
+
_make_dir(current, cwd)
|
|
224
|
+
|
|
225
|
+
if is_leaf:
|
|
226
|
+
if init:
|
|
227
|
+
_write_init(current / "__init__.py", cwd)
|
|
228
|
+
else:
|
|
229
|
+
if init_parents:
|
|
230
|
+
_write_init(current / "__init__.py", cwd)
|
|
231
|
+
|
|
232
|
+
typer.echo()
|
|
233
|
+
typer.echo(typer.style(f" ✓ module '{module_path}' ready.", fg=typer.colors.GREEN))
|
|
234
|
+
typer.echo()
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# ── ik module delete ──────────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
@module_app.command("delete")
|
|
240
|
+
def cmd_delete(
|
|
241
|
+
target: Path = typer.Argument(..., help="Module folder to delete."),
|
|
242
|
+
confirm: bool = typer.Option(
|
|
243
|
+
True, "--confirm/--no-confirm",
|
|
244
|
+
help="Prompt before deleting (default: on).",
|
|
245
|
+
),
|
|
246
|
+
) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Delete a module directory and everything inside it.
|
|
249
|
+
|
|
250
|
+
\b
|
|
251
|
+
Examples
|
|
252
|
+
--------
|
|
253
|
+
ik module delete core/models
|
|
254
|
+
ik module delete core/models --no-confirm
|
|
255
|
+
"""
|
|
256
|
+
cwd = Path.cwd()
|
|
257
|
+
path = (cwd / target).resolve()
|
|
258
|
+
|
|
259
|
+
if not path.exists():
|
|
260
|
+
_abort(f"Path not found: {target}")
|
|
261
|
+
|
|
262
|
+
if not path.is_dir():
|
|
263
|
+
_abort(f"Not a directory: {target}")
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
path.relative_to(cwd)
|
|
267
|
+
except ValueError:
|
|
268
|
+
_abort("Cannot delete a path outside the current working directory.")
|
|
269
|
+
|
|
270
|
+
if path == cwd:
|
|
271
|
+
_abort("Cannot delete the current working directory.")
|
|
272
|
+
|
|
273
|
+
rel = path.relative_to(cwd)
|
|
274
|
+
file_count = sum(1 for f in path.rglob("*") if f.is_file())
|
|
275
|
+
|
|
276
|
+
typer.echo()
|
|
277
|
+
typer.echo(
|
|
278
|
+
typer.style(" About to delete: ", fg=typer.colors.BRIGHT_BLACK)
|
|
279
|
+
+ typer.style(str(rel), fg=typer.colors.YELLOW, bold=True)
|
|
280
|
+
)
|
|
281
|
+
typer.echo(typer.style(f" Contains {file_count} file(s).", fg=typer.colors.BRIGHT_BLACK))
|
|
282
|
+
typer.echo()
|
|
283
|
+
|
|
284
|
+
if confirm:
|
|
285
|
+
typer.confirm(" Confirm delete?", abort=True)
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
shutil.rmtree(path)
|
|
289
|
+
except Exception as exc: # noqa: BLE001
|
|
290
|
+
_abort(f"Delete failed: {exc}")
|
|
291
|
+
|
|
292
|
+
typer.echo()
|
|
293
|
+
typer.echo(typer.style(f" ✓ Deleted {rel}", fg=typer.colors.GREEN))
|
|
294
|
+
typer.echo()
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# ── ik module tree ────────────────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
@module_app.command("tree")
|
|
300
|
+
def cmd_tree(
|
|
301
|
+
root: Optional[Path] = typer.Argument(
|
|
302
|
+
None,
|
|
303
|
+
help="Root directory to print. Defaults to cwd.",
|
|
304
|
+
),
|
|
305
|
+
show_ignored: bool = typer.Option(
|
|
306
|
+
False, "--show-ignored",
|
|
307
|
+
help="Include files and folders matched by .gitignore.",
|
|
308
|
+
),
|
|
309
|
+
) -> None:
|
|
310
|
+
"""
|
|
311
|
+
Print the directory tree of a project.
|
|
312
|
+
|
|
313
|
+
Reads .gitignore from the root directory and hides matched
|
|
314
|
+
entries by default. Pass --show-ignored to reveal them (dimmed).
|
|
315
|
+
|
|
316
|
+
\b
|
|
317
|
+
Examples
|
|
318
|
+
--------
|
|
319
|
+
ik module tree
|
|
320
|
+
ik module tree ./my-project
|
|
321
|
+
ik module tree --show-ignored
|
|
322
|
+
"""
|
|
323
|
+
target = (root or Path.cwd()).resolve()
|
|
324
|
+
|
|
325
|
+
if not target.exists():
|
|
326
|
+
_abort(f"Path not found: {target}")
|
|
327
|
+
if not target.is_dir():
|
|
328
|
+
_abort(f"Not a directory: {target}")
|
|
329
|
+
|
|
330
|
+
patterns = _load_gitignore_patterns(target)
|
|
331
|
+
|
|
332
|
+
typer.echo()
|
|
333
|
+
typer.echo(typer.style(target.name + "/", fg=typer.colors.CYAN, bold=True))
|
|
334
|
+
|
|
335
|
+
dirs, files = _render_tree(target, target, patterns, show_ignored)
|
|
336
|
+
|
|
337
|
+
typer.echo()
|
|
338
|
+
summary = typer.style(f" {dirs} director{'ies' if dirs != 1 else 'y'}, {files} file{'s' if files != 1 else ''}", fg=typer.colors.BRIGHT_BLACK)
|
|
339
|
+
if not show_ignored:
|
|
340
|
+
summary += typer.style(" (.gitignore applied — use --show-ignored to reveal)", fg=typer.colors.BRIGHT_BLACK)
|
|
341
|
+
typer.echo(summary)
|
|
342
|
+
typer.echo()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI commands for infrakit.time
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from infrakit.time import profile_script
|
|
10
|
+
|
|
11
|
+
time_app = typer.Typer(name = "time", help="Profile and time Python scripts", no_args_is_help=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@time_app.command(name="run")
|
|
15
|
+
def run_profiler(
|
|
16
|
+
script: Path = typer.Argument(
|
|
17
|
+
...,
|
|
18
|
+
help="Path to Python script to profile",
|
|
19
|
+
exists=True,
|
|
20
|
+
file_okay=True,
|
|
21
|
+
dir_okay=False,
|
|
22
|
+
),
|
|
23
|
+
max_functions: int = typer.Option(
|
|
24
|
+
30,
|
|
25
|
+
"--max-functions", "-n",
|
|
26
|
+
help="Maximum number of functions to display",
|
|
27
|
+
min=1,
|
|
28
|
+
),
|
|
29
|
+
min_time: float = typer.Option(
|
|
30
|
+
1.0,
|
|
31
|
+
"--min-time", "-t",
|
|
32
|
+
help="Minimum execution time in milliseconds to include",
|
|
33
|
+
min=0.0,
|
|
34
|
+
),
|
|
35
|
+
include_stdlib: bool = typer.Option(
|
|
36
|
+
False,
|
|
37
|
+
"--include-stdlib",
|
|
38
|
+
help="Include Python standard library calls in results",
|
|
39
|
+
),
|
|
40
|
+
):
|
|
41
|
+
"""
|
|
42
|
+
Profile a Python script using cProfile.
|
|
43
|
+
|
|
44
|
+
Executes the script under profiling and displays function-level timing statistics
|
|
45
|
+
in a clean, filtered table format.
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
|
|
49
|
+
# Basic profiling
|
|
50
|
+
ik time run myscript.py
|
|
51
|
+
|
|
52
|
+
# Show more functions, include faster calls
|
|
53
|
+
ik time run myscript.py --max-functions 50 --min-time 0.1
|
|
54
|
+
|
|
55
|
+
# Include stdlib calls
|
|
56
|
+
ik time run myscript.py --include-stdlib
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
# Run profiler (results printed automatically)
|
|
60
|
+
profile_script(
|
|
61
|
+
script_path=str(script),
|
|
62
|
+
max_functions=max_functions,
|
|
63
|
+
min_time_ms=min_time,
|
|
64
|
+
exclude_stdlib=not include_stdlib,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
except FileNotFoundError as e:
|
|
68
|
+
typer.secho(f"✗ {e}", fg=typer.colors.RED, err=True)
|
|
69
|
+
raise typer.Exit(1)
|
|
70
|
+
|
|
71
|
+
except RuntimeError as e:
|
|
72
|
+
typer.secho(f"✗ {e}", fg=typer.colors.RED, err=True)
|
|
73
|
+
raise typer.Exit(1)
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
typer.secho(f"✗ Unexpected error: {e}", fg=typer.colors.RED, err=True)
|
|
77
|
+
raise typer.Exit(1)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
time_app()
|
infrakit/cli/main.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
infrakit.cli.main
|
|
3
|
+
~~~~~~~~~~~~~~~~~
|
|
4
|
+
Root Typer app. Registered as both ``infrakit`` and ``ik`` in pyproject.toml.
|
|
5
|
+
|
|
6
|
+
[project.scripts]
|
|
7
|
+
infrakit = "infrakit.cli.main:main"
|
|
8
|
+
ik = "infrakit.cli.main:main"
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
|
|
13
|
+
from infrakit.cli.commands.config import config_app
|
|
14
|
+
from infrakit.cli.commands.logger import logger_app
|
|
15
|
+
from infrakit.cli.commands.module import module_app
|
|
16
|
+
from infrakit.cli.commands.init import cmd_init
|
|
17
|
+
from infrakit.cli.commands.time import time_app
|
|
18
|
+
from infrakit.cli.commands.deps import deps_app
|
|
19
|
+
from infrakit.cli.commands.llm import app as llm_app
|
|
20
|
+
|
|
21
|
+
app = typer.Typer(
|
|
22
|
+
name="infrakit",
|
|
23
|
+
help="infrakit — developer infrastructure toolkit.",
|
|
24
|
+
no_args_is_help=True,
|
|
25
|
+
pretty_exceptions_enable=False,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
app.add_typer(config_app, name="config")
|
|
29
|
+
app.add_typer(logger_app, name="logger")
|
|
30
|
+
app.add_typer(module_app, name="module")
|
|
31
|
+
app.add_typer(time_app, name="time")
|
|
32
|
+
app.add_typer(deps_app, name="deps")
|
|
33
|
+
app.add_typer(llm_app, name="llm")
|
|
34
|
+
app.command("init")(cmd_init)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _version_callback(value: bool) -> None:
|
|
38
|
+
if value:
|
|
39
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
40
|
+
try:
|
|
41
|
+
v = version("infrakit")
|
|
42
|
+
except PackageNotFoundError:
|
|
43
|
+
v = "dev"
|
|
44
|
+
typer.echo(f"infrakit {v}")
|
|
45
|
+
raise typer.Exit()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@app.callback()
|
|
49
|
+
def root(
|
|
50
|
+
version: bool = typer.Option(
|
|
51
|
+
False, "--version", "-V",
|
|
52
|
+
callback=_version_callback,
|
|
53
|
+
is_eager=True,
|
|
54
|
+
help="Print version and exit.",
|
|
55
|
+
),
|
|
56
|
+
) -> None:
|
|
57
|
+
"""infrakit — developer infrastructure toolkit."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main() -> None: # pragma: no cover
|
|
61
|
+
app()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__": # pragma: no cover
|
|
65
|
+
main()
|
|
File without changes
|
|
File without changes
|