codigest 0.3.7__tar.gz → 0.3.9__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.
- {codigest-0.3.7 → codigest-0.3.9}/PKG-INFO +5 -5
- {codigest-0.3.7 → codigest-0.3.9}/pyproject.toml +4 -4
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/diff.py +15 -23
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/digest.py +16 -24
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/scan.py +13 -12
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/semdiff.py +16 -24
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/tree.py +20 -11
- codigest-0.3.9/src/codigest/core/output.py +50 -0
- codigest-0.3.9/src/codigest/options.py +31 -0
- {codigest-0.3.7 → codigest-0.3.9}/uv.lock +1 -1
- {codigest-0.3.7 → codigest-0.3.9}/.github/workflows/publish.yml +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/.gitignore +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/.python-version +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/README.md +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/__init__.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/__main__.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/clean.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/init.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/commands/status.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/config.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/cache.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/common.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/git_ops.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/processor.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/prompts.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/resolver.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/scanner.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/semdiff.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/shadow.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/structure.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/tags.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/core/tokenizer.py +0 -0
- {codigest-0.3.7 → codigest-0.3.9}/src/codigest/main.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: codigest
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Human-Centered Codebase Context Manager for LLMs
|
|
5
|
-
Project-URL: Homepage, https://github.com/
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
5
|
+
Project-URL: Homepage, https://github.com/NaNIsaac/codigest
|
|
6
|
+
Project-URL: Repository, https://github.com/NaNIsaac/codigest
|
|
7
|
+
Project-URL: Issues, https://github.com/NaNIsaac/codigest/issues
|
|
8
8
|
Author-email: Codigest Team <sngd024@google.com>
|
|
9
9
|
License: MIT
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "codigest"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.9"
|
|
4
4
|
description = "Human-Centered Codebase Context Manager for LLMs"
|
|
5
5
|
authors = [{name = "Codigest Team", email = "sngd024@google.com"}]
|
|
6
6
|
readme = "README.md"
|
|
@@ -26,9 +26,9 @@ classifiers = [
|
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
[project.urls]
|
|
29
|
-
Homepage = "https://github.com/
|
|
30
|
-
Repository = "https://github.com/
|
|
31
|
-
Issues = "https://github.com/
|
|
29
|
+
Homepage = "https://github.com/NaNIsaac/codigest"
|
|
30
|
+
Repository = "https://github.com/NaNIsaac/codigest"
|
|
31
|
+
Issues = "https://github.com/NaNIsaac/codigest/issues"
|
|
32
32
|
|
|
33
33
|
[project.scripts]
|
|
34
34
|
codigest = "codigest.main:app"
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import typer
|
|
2
|
-
import pyperclip
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
from rich.console import Console
|
|
5
3
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
6
4
|
|
|
5
|
+
from ..options import CopyOption, StdoutOption, ResolveOption, MessageOption
|
|
7
6
|
from ..core import prompts, shadow, tags, common
|
|
7
|
+
from ..core.output import OutputHandler
|
|
8
8
|
|
|
9
9
|
app = typer.Typer()
|
|
10
|
-
console = Console()
|
|
11
|
-
err_console = Console(stderr=True)
|
|
12
10
|
|
|
13
11
|
@app.callback(invoke_without_command=True)
|
|
14
12
|
def handle(
|
|
@@ -20,18 +18,18 @@ def handle(
|
|
|
20
18
|
dir_okay=True,
|
|
21
19
|
resolve_path=True
|
|
22
20
|
),
|
|
23
|
-
copy:
|
|
21
|
+
copy: CopyOption = True,
|
|
24
22
|
save: bool = typer.Option(True, help="Save to .codigest/changes.diff"),
|
|
25
|
-
stdout:
|
|
26
|
-
message:
|
|
27
|
-
|
|
28
|
-
resolve: bool = typer.Option(False, "-r", "--resolve", help="Recursively resolve imports"),
|
|
23
|
+
stdout: StdoutOption = False,
|
|
24
|
+
message: MessageOption = "",
|
|
25
|
+
resolve: ResolveOption = False,
|
|
29
26
|
):
|
|
30
27
|
"""
|
|
31
28
|
[Context Update] Shows changes since the last 'codigest scan'.
|
|
32
29
|
Useful for updating LLM context without re-uploading everything.
|
|
33
30
|
"""
|
|
34
|
-
|
|
31
|
+
handler = OutputHandler(stdout=stdout, copy=copy)
|
|
32
|
+
log_console = handler.log_console
|
|
35
33
|
|
|
36
34
|
# [1] Context Setup
|
|
37
35
|
ctx = common.get_context(target)
|
|
@@ -87,17 +85,11 @@ def handle(
|
|
|
87
85
|
# [4] Output
|
|
88
86
|
log_console.print(f"[bold green]Changes Detected![/bold green] ({len(formatted_diff)} chars)")
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
log_console.print("[dim]
|
|
88
|
+
def _save():
|
|
89
|
+
if save:
|
|
90
|
+
out_path = root_path / ".codigest" / "changes.diff"
|
|
91
|
+
out_path.parent.mkdir(exist_ok=True)
|
|
92
|
+
out_path.write_text(formatted_diff, encoding="utf-8")
|
|
93
|
+
log_console.print(f"[dim]Saved to {out_path}[/dim]")
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
print(formatted_diff)
|
|
99
|
-
elif save:
|
|
100
|
-
out_path = root_path / ".codigest" / "changes.diff"
|
|
101
|
-
out_path.parent.mkdir(exist_ok=True)
|
|
102
|
-
out_path.write_text(formatted_diff, encoding="utf-8")
|
|
103
|
-
log_console.print(f"[dim]Saved to {out_path}[/dim]")
|
|
95
|
+
handler.handle_output(formatted_diff, save_action=_save, item_name="diff")
|
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
import typer
|
|
2
|
-
import pyperclip
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
from rich.console import Console
|
|
5
3
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
6
4
|
|
|
5
|
+
from ..options import CopyOption, StdoutOption, ResolveOption, MessageOption
|
|
7
6
|
from ..core import structure, prompts, semdiff, tags, tokenizer, common, cache
|
|
7
|
+
from ..core.output import OutputHandler
|
|
8
8
|
|
|
9
9
|
app = typer.Typer()
|
|
10
|
-
console = Console()
|
|
11
|
-
err_console = Console(stderr=True)
|
|
12
10
|
|
|
13
11
|
@app.callback(invoke_without_command=True)
|
|
14
12
|
def handle(
|
|
15
13
|
target: Path = typer.Argument(Path.cwd(), help="Target directory"),
|
|
16
|
-
copy:
|
|
14
|
+
copy: CopyOption = True,
|
|
17
15
|
save: bool = typer.Option(True, help="Save to .codigest/digest.txt"),
|
|
18
|
-
stdout:
|
|
19
|
-
message:
|
|
20
|
-
|
|
21
|
-
resolve: bool = typer.Option(False, "-r", "--resolve", help="Recursively resolve imports"),
|
|
16
|
+
stdout: StdoutOption = False,
|
|
17
|
+
message: MessageOption = "",
|
|
18
|
+
resolve: ResolveOption = False,
|
|
22
19
|
):
|
|
23
20
|
"""
|
|
24
21
|
[Architectural View] Summarizes the codebase structure (Classes/Functions only).
|
|
25
22
|
"""
|
|
26
|
-
|
|
23
|
+
handler = OutputHandler(stdout=stdout, copy=copy)
|
|
24
|
+
log_console = handler.log_console
|
|
27
25
|
|
|
28
26
|
# [1] Context Setup
|
|
29
27
|
ctx = common.get_context(target)
|
|
@@ -92,17 +90,11 @@ def handle(
|
|
|
92
90
|
token_count = tokenizer.estimate_tokens(digest_content)
|
|
93
91
|
log_console.print(f"[bold green]Digest Generated![/bold green] ([bold cyan]~{token_count:,} Tokens[/bold cyan])")
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
log_console.print("[dim]
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
print(digest_content)
|
|
104
|
-
elif save:
|
|
105
|
-
out_path = root_path / ".codigest" / "digest.txt"
|
|
106
|
-
out_path.parent.mkdir(exist_ok=True)
|
|
107
|
-
out_path.write_text(digest_content, encoding="utf-8")
|
|
108
|
-
log_console.print(f"[dim]💾 Saved to {out_path}[/dim]")
|
|
93
|
+
def _save():
|
|
94
|
+
if save:
|
|
95
|
+
out_path = root_path / ".codigest" / "digest.txt"
|
|
96
|
+
out_path.parent.mkdir(exist_ok=True)
|
|
97
|
+
out_path.write_text(digest_content, encoding="utf-8")
|
|
98
|
+
log_console.print(f"[dim]💾 Saved to {out_path}[/dim]")
|
|
99
|
+
|
|
100
|
+
handler.handle_output(digest_content, save_action=_save, item_name="digest")
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import typer
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from rich.console import Console
|
|
5
4
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
6
5
|
from rich.panel import Panel
|
|
7
6
|
from rich.filesize import decimal
|
|
8
7
|
|
|
8
|
+
from ..options import CopyOption, StdoutOption, ResolveOption, MessageOption, AllOption
|
|
9
9
|
from ..core import structure, tags, prompts, processor, shadow, tokenizer, common, cache
|
|
10
|
+
from ..core.output import OutputHandler
|
|
10
11
|
|
|
11
12
|
app = typer.Typer()
|
|
12
|
-
console = Console()
|
|
13
|
-
err_console = Console(stderr=True)
|
|
14
13
|
|
|
15
14
|
@app.callback(invoke_without_command=True)
|
|
16
15
|
def handle(
|
|
@@ -21,18 +20,20 @@ def handle(
|
|
|
21
20
|
resolve_path=True
|
|
22
21
|
),
|
|
23
22
|
output: str = typer.Option("snapshot.txt", "-o", "--output", help="Output filename inside .codigest/"),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
copy: CopyOption = True,
|
|
24
|
+
stdout: StdoutOption = False,
|
|
25
|
+
all: AllOption = False,
|
|
26
|
+
message: MessageOption = "",
|
|
27
27
|
line_numbers: bool = typer.Option(False, "--lines", "-l", help="Add line numbers to code blocks"),
|
|
28
28
|
yes: bool = typer.Option(False, "-y", "--yes", help="Skip confirmation prompt"),
|
|
29
|
-
resolve:
|
|
29
|
+
resolve: ResolveOption = False,
|
|
30
30
|
):
|
|
31
31
|
"""
|
|
32
32
|
Scans the codebase.
|
|
33
33
|
If TARGETS provided, only scans those paths within the project.
|
|
34
34
|
"""
|
|
35
|
-
|
|
35
|
+
handler = OutputHandler(stdout=stdout, copy=copy)
|
|
36
|
+
log_console = handler.log_console
|
|
36
37
|
|
|
37
38
|
# [1] Context Setup (Centralized)
|
|
38
39
|
ctx = common.get_context(targets)
|
|
@@ -168,9 +169,7 @@ def handle(
|
|
|
168
169
|
except Exception as e:
|
|
169
170
|
log_console.print(f"[yellow][Warning] Failed to update context anchor: {e}[/yellow]")
|
|
170
171
|
|
|
171
|
-
|
|
172
|
-
print(snapshot_content)
|
|
173
|
-
else:
|
|
172
|
+
def _save():
|
|
174
173
|
try:
|
|
175
174
|
output_path.write_text(snapshot_content, encoding="utf-8")
|
|
176
175
|
final_token_count = tokenizer.estimate_tokens(snapshot_content)
|
|
@@ -186,4 +185,6 @@ def handle(
|
|
|
186
185
|
|
|
187
186
|
except Exception as e:
|
|
188
187
|
log_console.print(f"[bold red][Error] Save Failed:[/bold red] {e}")
|
|
189
|
-
raise typer.Exit(1)
|
|
188
|
+
raise typer.Exit(1)
|
|
189
|
+
|
|
190
|
+
handler.handle_output(snapshot_content, save_action=_save)
|
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
import typer
|
|
2
|
-
import pyperclip
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
from rich.console import Console
|
|
5
3
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
6
4
|
|
|
5
|
+
from ..options import CopyOption, StdoutOption, ResolveOption, MessageOption
|
|
7
6
|
from ..core import prompts, shadow, semdiff, tags, tokenizer, common
|
|
7
|
+
from ..core.output import OutputHandler
|
|
8
8
|
|
|
9
9
|
app = typer.Typer()
|
|
10
|
-
console = Console()
|
|
11
|
-
err_console = Console(stderr=True)
|
|
12
10
|
|
|
13
11
|
@app.callback(invoke_without_command=True)
|
|
14
12
|
def handle(
|
|
15
13
|
target: Path = typer.Argument(Path.cwd(), help="Target directory"),
|
|
16
|
-
copy:
|
|
14
|
+
copy: CopyOption = True,
|
|
17
15
|
save: bool = typer.Option(True, help="Save to .codigest/semdiff.txt"),
|
|
18
|
-
stdout:
|
|
19
|
-
message:
|
|
20
|
-
|
|
21
|
-
resolve: bool = typer.Option(False, "-r", "--resolve", help="Recursively resolve imports"),
|
|
16
|
+
stdout: StdoutOption = False,
|
|
17
|
+
message: MessageOption = "",
|
|
18
|
+
resolve: ResolveOption = False,
|
|
22
19
|
):
|
|
23
20
|
"""
|
|
24
21
|
[Advanced] Generates a Semantic Diff (AST-based) report.
|
|
25
22
|
Shows ADDED/REMOVED/MODIFIED functions & classes instead of raw text lines.
|
|
26
23
|
"""
|
|
27
|
-
|
|
24
|
+
handler = OutputHandler(stdout=stdout, copy=copy)
|
|
25
|
+
log_console = handler.log_console
|
|
28
26
|
|
|
29
27
|
# [1] Context Setup
|
|
30
28
|
ctx = common.get_context(target)
|
|
@@ -134,17 +132,11 @@ def handle(
|
|
|
134
132
|
token_count = tokenizer.estimate_tokens(final_output)
|
|
135
133
|
log_console.print(f"[bold green]SemDiff Generated![/bold green] ([bold cyan]~{token_count:,} Tokens[/bold cyan])")
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
log_console.print("[dim]
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
print(final_output)
|
|
146
|
-
elif save:
|
|
147
|
-
out_path = root_path / ".codigest" / "semdiff.txt"
|
|
148
|
-
out_path.parent.mkdir(exist_ok=True)
|
|
149
|
-
out_path.write_text(final_output, encoding="utf-8")
|
|
150
|
-
log_console.print(f"[dim]Saved to {out_path}[/dim]")
|
|
135
|
+
def _save():
|
|
136
|
+
if save:
|
|
137
|
+
out_path = root_path / ".codigest" / "semdiff.txt"
|
|
138
|
+
out_path.parent.mkdir(exist_ok=True)
|
|
139
|
+
out_path.write_text(final_output, encoding="utf-8")
|
|
140
|
+
log_console.print(f"[dim]Saved to {out_path}[/dim]")
|
|
141
|
+
|
|
142
|
+
handler.handle_output(final_output, save_action=_save, item_name="semdiff")
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import typer
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from rich.console import Console
|
|
4
3
|
from rich.tree import Tree
|
|
5
4
|
from rich.text import Text
|
|
6
5
|
from rich.filesize import decimal
|
|
7
6
|
|
|
8
|
-
from ..
|
|
7
|
+
from ..options import CopyOption, StdoutOption, ResolveOption, AllOption
|
|
8
|
+
from ..core import common, structure
|
|
9
|
+
from ..core.output import OutputHandler
|
|
9
10
|
|
|
10
11
|
app = typer.Typer()
|
|
11
|
-
console = Console()
|
|
12
12
|
|
|
13
13
|
def _build_rich_tree(root_path: Path, files: list[Path]) -> Tree:
|
|
14
14
|
# (기존의 이모티콘 없는 버전 로직 유지)
|
|
@@ -16,7 +16,6 @@ def _build_rich_tree(root_path: Path, files: list[Path]) -> Tree:
|
|
|
16
16
|
dir_nodes = {root_path: tree}
|
|
17
17
|
|
|
18
18
|
for path in files:
|
|
19
|
-
# (중략: 기존 트리 생성 로직)
|
|
20
19
|
# External path 처리 (루트 밖의 파일)
|
|
21
20
|
try:
|
|
22
21
|
relative = path.relative_to(root_path)
|
|
@@ -54,12 +53,17 @@ def _build_rich_tree(root_path: Path, files: list[Path]) -> Tree:
|
|
|
54
53
|
@app.callback(invoke_without_command=True)
|
|
55
54
|
def handle(
|
|
56
55
|
target: Path = typer.Argument(Path.cwd(), help="Target directory"),
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
copy: CopyOption = False,
|
|
57
|
+
stdout: StdoutOption = False,
|
|
58
|
+
all: AllOption = False,
|
|
59
|
+
resolve: ResolveOption = False,
|
|
59
60
|
):
|
|
60
61
|
"""
|
|
61
62
|
[Visual] Print the project directory tree.
|
|
62
63
|
"""
|
|
64
|
+
handler = OutputHandler(stdout=stdout, copy=copy)
|
|
65
|
+
log_console = handler.log_console
|
|
66
|
+
|
|
63
67
|
# 1. Context 생성 (루트 찾기용)
|
|
64
68
|
ctx = common.get_context(target)
|
|
65
69
|
root_path = ctx.root_path
|
|
@@ -69,14 +73,19 @@ def handle(
|
|
|
69
73
|
# [수정] targets=[target]을 명시적으로 전달해야 해당 폴더만 스캔함
|
|
70
74
|
files = ctx.get_target_files(targets=[target], ignore_config=all, resolve_deps=resolve)
|
|
71
75
|
except Exception as e:
|
|
72
|
-
|
|
76
|
+
log_console.print(f"[red][Error] Scan failed:[/red] {e}")
|
|
73
77
|
raise typer.Exit(code=1)
|
|
74
78
|
|
|
75
79
|
if not files:
|
|
76
|
-
|
|
80
|
+
log_console.print("[yellow][Warning] No matching files found.[/yellow]")
|
|
77
81
|
return
|
|
78
82
|
|
|
79
83
|
# 3. Visualize
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
ascii_tree = structure.generate_ascii_tree(files, root_path)
|
|
85
|
+
|
|
86
|
+
def _print_tree_viz():
|
|
87
|
+
tree_viz = _build_rich_tree(root_path, files)
|
|
88
|
+
log_console.print(tree_viz)
|
|
89
|
+
log_console.print(f"\n[dim]Found {len(files)} files.[/dim]")
|
|
90
|
+
|
|
91
|
+
handler.handle_output(ascii_tree, save_action=_print_tree_viz, item_name="tree")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified Output Handler for CLI commands.
|
|
3
|
+
Manages stderr log console, clipboard copying, and file vs stdout output.
|
|
4
|
+
"""
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Callable, Optional
|
|
7
|
+
import pyperclip
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
err_console = Console(stderr=True)
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class OutputHandler:
|
|
15
|
+
stdout: bool = False
|
|
16
|
+
copy: bool = True
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def log_console(self) -> Console:
|
|
20
|
+
"""
|
|
21
|
+
Returns err_console (stderr) when output is directed to stdout,
|
|
22
|
+
ensuring progress/logs do not pollute stdout pipelines.
|
|
23
|
+
"""
|
|
24
|
+
return err_console if self.stdout else console
|
|
25
|
+
|
|
26
|
+
def copy_to_clipboard(self, content: str, item_name: str = "output"):
|
|
27
|
+
"""Copies content to clipboard safely."""
|
|
28
|
+
if not self.copy:
|
|
29
|
+
return
|
|
30
|
+
try:
|
|
31
|
+
pyperclip.copy(content)
|
|
32
|
+
self.log_console.print(f"[dim]📋 Copied {item_name} to clipboard[/dim]")
|
|
33
|
+
except Exception:
|
|
34
|
+
self.log_console.print("[dim]⚠️ Clipboard unavailable (skipped copy)[/dim]")
|
|
35
|
+
|
|
36
|
+
def handle_output(
|
|
37
|
+
self,
|
|
38
|
+
content: str,
|
|
39
|
+
save_action: Optional[Callable[[], None]] = None,
|
|
40
|
+
item_name: str = "output"
|
|
41
|
+
):
|
|
42
|
+
"""
|
|
43
|
+
Executes clipboard copy, stdout print, or file save action cleanly.
|
|
44
|
+
"""
|
|
45
|
+
self.copy_to_clipboard(content, item_name=item_name)
|
|
46
|
+
|
|
47
|
+
if self.stdout:
|
|
48
|
+
print(content)
|
|
49
|
+
elif save_action:
|
|
50
|
+
save_action()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized CLI Options & Common Annotated Types.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
# Common CLI Option Types using typing.Annotated
|
|
8
|
+
CopyOption = Annotated[
|
|
9
|
+
bool,
|
|
10
|
+
typer.Option("-c", "--copy/--no-copy", help="Auto-copy output to clipboard")
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
StdoutOption = Annotated[
|
|
14
|
+
bool,
|
|
15
|
+
typer.Option("-s", "--stdout", help="Print output to terminal (stdout) instead of file")
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
ResolveOption = Annotated[
|
|
19
|
+
bool,
|
|
20
|
+
typer.Option("-r", "--resolve", help="Recursively resolve imports")
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
MessageOption = Annotated[
|
|
24
|
+
str,
|
|
25
|
+
typer.Option("-m", "--message", help="Add specific instruction context")
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
AllOption = Annotated[
|
|
29
|
+
bool,
|
|
30
|
+
typer.Option("-a", "--all", help="Ignore config filters")
|
|
31
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|