clinkey-cli 1.0.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dimitri Gaggioli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: clinkey-cli
3
+ Version: 1.0.0
4
+ Summary: A command-line tool for generating strong passwords and secret keys.
5
+ Author: Clinkey
6
+ License-Expression: MIT
7
+ Keywords: password,cli,security
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Environment :: Console
11
+ Classifier: Topic :: Security
12
+ Classifier: Topic :: Utilities
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: click>=8.1.0
17
+ Requires-Dist: rich>=13.0.0
18
+ Dynamic: license-file
19
+
20
+ ![](clinkey_preview.png)
21
+
22
+ ---
23
+ ```bash
24
+ Your password generator *'buddy'*, available on a CLI.
25
+ ```
26
+ ---
27
+ ```bash
28
+ Usage python3 heat.py clinkey [OPTIONS]
29
+ ```
30
+ ---
31
+ ```bash
32
+ -l, --length The desired length for the output password(s)
33
+ -n, --number The amount of password you are expecting from ClinKey to generate.
34
+ -o, --output The path of a file in which to print the result instead of echoing it into the Terminal.
35
+ -t --type The strength and complexity of the password content.
36
+ Possible values:
37
+ - 'normal' - Containing only alphabetical characters.
38
+ - 'strong' - Mixing letters and digits.
39
+ - 'super_strong' - Adding special characters to the result.
40
+ -ns, --no-sep Clear the result from the hyphens used to separate the groups of letters usually forming the result.
41
+ -low, --lower Transform the output password in lowercase string.
@@ -0,0 +1,22 @@
1
+ ![](clinkey_preview.png)
2
+
3
+ ---
4
+ ```bash
5
+ Your password generator *'buddy'*, available on a CLI.
6
+ ```
7
+ ---
8
+ ```bash
9
+ Usage python3 heat.py clinkey [OPTIONS]
10
+ ```
11
+ ---
12
+ ```bash
13
+ -l, --length The desired length for the output password(s)
14
+ -n, --number The amount of password you are expecting from ClinKey to generate.
15
+ -o, --output The path of a file in which to print the result instead of echoing it into the Terminal.
16
+ -t --type The strength and complexity of the password content.
17
+ Possible values:
18
+ - 'normal' - Containing only alphabetical characters.
19
+ - 'strong' - Mixing letters and digits.
20
+ - 'super_strong' - Adding special characters to the result.
21
+ -ns, --no-sep Clear the result from the hyphens used to separate the groups of letters usually forming the result.
22
+ -low, --lower Transform the output password in lowercase string.
@@ -0,0 +1,6 @@
1
+ """clinkey-cli package public API."""
2
+
3
+ from .main import Clinkey, clinkey
4
+
5
+ __all__ = ["Clinkey", "clinkey"]
6
+ __version__ = "1.0.0"
@@ -0,0 +1,302 @@
1
+ """Click-based command line interface for the clinkey password generator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ from typing import Iterable, Optional
7
+
8
+ import click
9
+ from rich import box
10
+ from rich.align import Align
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.table import Table
14
+ from rich.text import Text
15
+
16
+ from .main import Clinkey
17
+
18
+
19
+ console = Console(style="on grey11")
20
+
21
+
22
+ class ClinkeyView:
23
+ """Render user interactions with Rich while mirroring the original styling."""
24
+
25
+ def __init__(self) -> None:
26
+ self._logo_style = {
27
+ "title_color": "light_green",
28
+ "accent_color": "orchid1",
29
+ "text_color": "grey100",
30
+ }
31
+
32
+ def _clear(self) -> None:
33
+ console.clear()
34
+
35
+ def _logo_panel(self) -> Panel:
36
+ logo = Text(
37
+ """
38
+ ╔═╝ ║ ╝ ╔═ ║ ║ ╔═╝ ║ ║
39
+ ║ ║ ║ ║ ║ ╔╝ ╔═╝ ═╔╝
40
+ ══╝ ══╝ ╝ ╝ ╝ ╝ ╝ ══╝ ╝
41
+ """,
42
+ style=self._logo_style["title_color"],
43
+ justify="center",
44
+ )
45
+ return Panel.fit(
46
+ logo,
47
+ padding=(0, 2),
48
+ box=box.ROUNDED,
49
+ border_style=self._logo_style["accent_color"],
50
+ )
51
+
52
+ def display_logo(self) -> None:
53
+ self._clear()
54
+ console.print("\n\n")
55
+ console.print(self._logo_panel(), justify="center")
56
+ subtitle = Text.from_markup(
57
+ "Your own [bold light_green]SECRET BUDDY[/]...\n\n",
58
+ style="white",
59
+ justify="center",
60
+ )
61
+ console.print(Align.center(subtitle))
62
+ prompt = Text.from_markup(
63
+ "Press [bold light_green]ENTER[/] to continue...\n\n",
64
+ style="white",
65
+ )
66
+ console.print(Align.center(prompt), end="")
67
+ input()
68
+
69
+ def ask_for_type(self) -> str:
70
+ self._clear()
71
+ console.print(self._logo_panel(), justify="center")
72
+ console.print(
73
+ Align.center(
74
+ Text.from_markup(
75
+ "How [bold light_green]BOLD[/] do you want your password?\n",
76
+ style="white",
77
+ )
78
+ )
79
+ )
80
+ choices = Text.from_markup(
81
+ "1 - [bold orchid1]Vanilla[/] (letters only)\n"
82
+ "2 - [bold orchid1]Spicy[/] (letters and digits)\n"
83
+ "3 - [bold orchid1]Inferno[/] (letters, digits, symbols)",
84
+ style="white",
85
+ )
86
+ console.print(Align.center(choices))
87
+ console.print(
88
+ Align.center(
89
+ Text.from_markup(
90
+ "Choose your [bold light_green]TRIBE[/] (1 / 2 / 3): ",
91
+ style="bright_black",
92
+ )
93
+ ),
94
+ end="",
95
+ )
96
+ choice = input().strip()
97
+ return {"1": "normal", "2": "strong", "3": "super_strong"}.get(choice, "normal")
98
+
99
+ def ask_for_length(self) -> int:
100
+ self._clear()
101
+ console.print(self._logo_panel(), justify="center")
102
+ console.print(
103
+ Align.center(
104
+ Text.from_markup(
105
+ "How [bold light_green]LONG[/] should it be?",
106
+ style="white",
107
+ )
108
+ )
109
+ )
110
+ console.print(
111
+ Align.center(Text.from_markup("(default: 16): ", style="bright_black")),
112
+ end="",
113
+ )
114
+ value = input().strip()
115
+ try:
116
+ length = int(value)
117
+ return length if length > 0 else 16
118
+ except ValueError:
119
+ return 16
120
+
121
+ def ask_for_number(self) -> int:
122
+ self._clear()
123
+ console.print(self._logo_panel(), justify="center")
124
+ console.print(
125
+ Align.center(
126
+ Text.from_markup(
127
+ "How [bold light_green]MANY[/] passwords do you need?",
128
+ style="white",
129
+ )
130
+ )
131
+ )
132
+ console.print(
133
+ Align.center(Text.from_markup("(default: 1): ", style="bright_black")),
134
+ end="",
135
+ )
136
+ value = input().strip()
137
+ try:
138
+ count = int(value)
139
+ return count if count > 0 else 1
140
+ except ValueError:
141
+ return 1
142
+
143
+ def ask_for_options(self) -> list[str]:
144
+ self._clear()
145
+ console.print(self._logo_panel(), justify="center")
146
+ console.print(
147
+ Align.center(
148
+ Text.from_markup(
149
+ "Any extra [bold light_green]OPTIONS[/]? (separate by spaces)",
150
+ style="white",
151
+ )
152
+ )
153
+ )
154
+ console.print(
155
+ Align.center(Text.from_markup("Available: lower, no_sep", style="bright_black"))
156
+ )
157
+ choices = input().strip()
158
+ return choices.split() if choices else []
159
+
160
+ def ask_for_output_path(self) -> Optional[str]:
161
+ self._clear()
162
+ console.print(self._logo_panel(), justify="center")
163
+ console.print(
164
+ Align.center(
165
+ Text.from_markup(
166
+ "Enter a file path to save the result (press ENTER to skip):",
167
+ style="white",
168
+ )
169
+ ),
170
+ end="",
171
+ )
172
+ value = input().strip()
173
+ return value or None
174
+
175
+ def display_passwords(self, passwords: Iterable[str]) -> None:
176
+ self._clear()
177
+ console.print(self._logo_panel(), justify="center")
178
+ console.print(
179
+ Panel.fit(
180
+ Align.center(
181
+ Text.from_markup(
182
+ "Your Clinkey [bold light_green]PASSWORDS[/] are [bold light_green]READY[/]",
183
+ style="white",
184
+ )
185
+ ),
186
+ padding=(0, 1),
187
+ box=box.ROUNDED,
188
+ border_style=self._logo_style["accent_color"],
189
+ ),
190
+ justify="center",
191
+ )
192
+ table = Table(show_header=False, box=box.ROUNDED, border_style=self._logo_style["accent_color"])
193
+ table.add_column("password", style=self._logo_style["title_color"], justify="center")
194
+ for password in passwords:
195
+ table.add_row(Text(password, style="white", justify="center"))
196
+ console.print(table, justify="center")
197
+
198
+ console.print(
199
+ Align.center(
200
+ Text.from_markup("Choose one to copy and stay safe!", style="bright_black"),
201
+ )
202
+ )
203
+
204
+
205
+ view = ClinkeyView()
206
+
207
+ def _parse_extra_options(options: Iterable[str]) -> dict[str, bool]:
208
+ lookup = {
209
+ "lower": {"lower", "low", "-l", "--lower"},
210
+ "no_sep": {"no_sep", "nosep", "-ns", "--no-sep", "no-sep", "ns"},
211
+ }
212
+ result = {"lower": False, "no_sep": False}
213
+ for option in options:
214
+ token = option.strip().lower()
215
+ for key, aliases in lookup.items():
216
+ if token in aliases:
217
+ result[key] = True
218
+ return result
219
+
220
+
221
+ def _write_passwords(path: pathlib.Path, passwords: Iterable[str]) -> None:
222
+ with path.open("w", encoding="utf-8") as handle:
223
+ for password in passwords:
224
+ handle.write(f"{password}\n")
225
+
226
+
227
+ @click.command(context_settings={"help_option_names": ["-h", "--help"]})
228
+ @click.option("-l", "--length", type=int, default=None, help="Password length (default: 16).")
229
+ @click.option(
230
+ "-t",
231
+ "--type",
232
+ "type_",
233
+ type=click.Choice(["normal", "strong", "super_strong"], case_sensitive=False),
234
+ default=None,
235
+ help="Password profile: normal, strong, or super_strong.",
236
+ )
237
+ @click.option(
238
+ "-n",
239
+ "--number",
240
+ type=int,
241
+ default=None,
242
+ help="Number of passwords to generate (default: 1).",
243
+ )
244
+ @click.option("-ns", "--no-sep", "no_sep", is_flag=True, help="Remove separators from the result.")
245
+ @click.option("-low", "--lower", is_flag=True, help="Convert generated passwords to lowercase.")
246
+ @click.option(
247
+ "-o",
248
+ "--output",
249
+ type=click.Path(dir_okay=False, writable=True, resolve_path=True, path_type=pathlib.Path),
250
+ default=None,
251
+ help="Write the result to a file instead of displaying it.",
252
+ )
253
+ def main(
254
+ length: Optional[int],
255
+ type_: Optional[str],
256
+ number: Optional[int],
257
+ no_sep: bool,
258
+ lower: bool,
259
+ output: Optional[pathlib.Path],
260
+ ) -> None:
261
+ """Generate secure, pronounceable passwords from your terminal."""
262
+
263
+ generator = Clinkey()
264
+
265
+ interactive = length is None and type_ is None and number is None
266
+
267
+ if interactive:
268
+ view.display_logo()
269
+ length = view.ask_for_length()
270
+ type_ = view.ask_for_type()
271
+ number = view.ask_for_number()
272
+ extra = _parse_extra_options(view.ask_for_options())
273
+ lower = extra["lower"]
274
+ no_sep = extra["no_sep"]
275
+ chosen_output = view.ask_for_output_path()
276
+ if chosen_output:
277
+ output = pathlib.Path(chosen_output).expanduser().resolve()
278
+
279
+ length = 16 if length is None else length
280
+ type_ = "normal" if type_ is None else type_.lower()
281
+ number = 1 if number is None else number
282
+
283
+ passwords = generator.generate_batch(
284
+ length=length,
285
+ type=type_,
286
+ count=number,
287
+ lower=lower,
288
+ no_separator=no_sep,
289
+ )
290
+
291
+ if output:
292
+ _write_passwords(output, passwords)
293
+ click.echo(f"Passwords saved to {output}")
294
+ elif interactive:
295
+ view.display_passwords(passwords)
296
+ else:
297
+ for password in passwords:
298
+ click.echo(password)
299
+
300
+
301
+ if __name__ == "__main__": # pragma: no cover
302
+ main()
@@ -0,0 +1,225 @@
1
+ """Core password generation logic for the Clinkey CLI package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import random
6
+ import string
7
+ from typing import Callable, Dict
8
+
9
+
10
+ class Clinkey:
11
+ """Generate pronounceable passwords with different complexity presets."""
12
+
13
+ def __init__(self) -> None:
14
+ alphabet = string.ascii_uppercase
15
+ vowels = "AEIOUY"
16
+ self._consonants = [char for char in alphabet if char not in vowels]
17
+ self._vowels = list(vowels)
18
+ self._digits = list(string.digits)
19
+ self._specials = [
20
+ char
21
+ for char in string.punctuation
22
+ if char not in {"-", "_", "$", "#", "|", "<", ">", "(", ")", "[", "]", "{", "}", '"', "'", "`", "@", " "}
23
+ ]
24
+
25
+ self._simple_syllables = [consonant + vowel for consonant in self._consonants for vowel in self._vowels]
26
+ self._complex_syllables = [
27
+ "TRE",
28
+ "TRI",
29
+ "TRO",
30
+ "TRA",
31
+ "DRE",
32
+ "DRI",
33
+ "DRO",
34
+ "DRA",
35
+ "BRE",
36
+ "BRI",
37
+ "BRO",
38
+ "BRA",
39
+ "CRE",
40
+ "CRI",
41
+ "CRO",
42
+ "CRA",
43
+ "FRE",
44
+ "FRI",
45
+ "FRO",
46
+ "FRA",
47
+ "GRE",
48
+ "GRI",
49
+ "GRO",
50
+ "GRA",
51
+ "PRE",
52
+ "PRI",
53
+ "PRO",
54
+ "PRA",
55
+ "SRE",
56
+ "SRI",
57
+ "SRO",
58
+ "SRA",
59
+ "VRE",
60
+ "VRI",
61
+ "VRO",
62
+ "VRA",
63
+ "ZRE",
64
+ "ZRI",
65
+ "ZRO",
66
+ "ZRA",
67
+ "LON",
68
+ "LEN",
69
+ "LIN",
70
+ "LAN",
71
+ "MON",
72
+ "MEN",
73
+ "MIN",
74
+ "MAN",
75
+ "NON",
76
+ "NEN",
77
+ "NIN",
78
+ "NAN",
79
+ "PON",
80
+ "PEN",
81
+ "PIN",
82
+ "PAN",
83
+ "RON",
84
+ "REN",
85
+ "RIN",
86
+ "RAN",
87
+ "SON",
88
+ "SEN",
89
+ "SIN",
90
+ "SAN",
91
+ "TON",
92
+ "TEN",
93
+ "TIN",
94
+ "TAN",
95
+ "VON",
96
+ "VEN",
97
+ "VIN",
98
+ "VAN",
99
+ "ZON",
100
+ "ZEN",
101
+ "ZIN",
102
+ "ZAN",
103
+ ]
104
+
105
+ self._separators = ["-", "_"]
106
+ self._generators: Dict[str, Callable[[], str]] = {
107
+ "normal": self.normal,
108
+ "strong": self.strong,
109
+ "super_strong": self.super_strong,
110
+ }
111
+
112
+ def _generate_simple_syllable(self) -> str:
113
+ return random.choice(self._simple_syllables)
114
+
115
+ def _generate_complex_syllable(self) -> str:
116
+ return random.choice(self._complex_syllables)
117
+
118
+ def _generate_pronounceable_word(self, min_length: int = 4, max_length: int = 8) -> str:
119
+ word = self._generate_simple_syllable()
120
+ target = random.randint(min_length, max_length)
121
+
122
+ while len(word) < target:
123
+ generator = random.choice([self._generate_simple_syllable, self._generate_complex_syllable])
124
+ word += generator()
125
+
126
+ return word[:target]
127
+
128
+ def _generate_number_block(self, length: int = 3) -> str:
129
+ return "".join(random.choices(self._digits, k=length))
130
+
131
+ def _generate_special_characters_block(self, length: int = 3) -> str:
132
+ return "".join(random.choices(self._specials, k=length))
133
+
134
+ def _generate_separator(self) -> str:
135
+ return random.choice(self._separators)
136
+
137
+ def super_strong(self) -> str:
138
+ words = [self._generate_pronounceable_word(random.randint(4, 6), random.randint(8, 12)) for _ in range(3)]
139
+ numbers = [self._generate_number_block(random.randint(3, 6)) for _ in range(3)]
140
+ specials = [self._generate_special_characters_block(random.randint(3, 6)) for _ in range(2)]
141
+ separators = [self._generate_separator() for _ in range(6)]
142
+
143
+ result = []
144
+ result.append(words.pop() + separators.pop() + specials.pop() + separators.pop() + numbers.pop() + separators.pop())
145
+ result.append(words.pop() + separators.pop() + specials.pop() + separators.pop() + numbers.pop() + separators.pop())
146
+ result.append(words.pop())
147
+ return "".join(result)
148
+
149
+ def strong(self) -> str:
150
+ words = [self._generate_pronounceable_word(random.randint(4, 6), random.randint(8, 12)) for _ in range(3)]
151
+ numbers = [self._generate_number_block(random.randint(3, 6)) for _ in range(3)]
152
+ separators = [self._generate_separator() for _ in range(6)]
153
+
154
+ result = []
155
+ for _ in range(3):
156
+ result.append(words.pop(0) + separators.pop(0) + numbers.pop(0) + separators.pop(0))
157
+ return "".join(result)
158
+
159
+ def normal(self) -> str:
160
+ words = [self._generate_pronounceable_word(random.randint(4, 6), random.randint(8, 12)) for _ in range(3)]
161
+ separators = [self._generate_separator() for _ in range(6)]
162
+
163
+ result = []
164
+ for _ in range(3):
165
+ result.append(words.pop(0) + separators.pop(0))
166
+ return "".join(result)
167
+
168
+ def _fit_to_length(self, generator: Callable[[], str], target_length: int) -> str:
169
+ password = ""
170
+ while len(password) < target_length:
171
+ chunk = generator()
172
+ if len(password) + len(chunk) <= target_length:
173
+ password += chunk
174
+ else:
175
+ remaining = target_length - len(password)
176
+ password += chunk[:remaining]
177
+ break
178
+ return password
179
+
180
+ def generate_password(
181
+ self,
182
+ length: int = 16,
183
+ type: str = "normal",
184
+ lower: bool = False,
185
+ no_separator: bool = False,
186
+ ) -> str:
187
+ if length <= 0:
188
+ raise ValueError("length must be a positive integer")
189
+
190
+ key = type.strip().lower()
191
+ if key not in self._generators:
192
+ valid = ", ".join(sorted(self._generators.keys()))
193
+ raise ValueError(f"Unsupported type '{type}'. Choose among: {valid}.")
194
+
195
+ raw_password = self._fit_to_length(self._generators[key], length)
196
+ cleaned = raw_password.strip("-_")
197
+
198
+ if no_separator:
199
+ cleaned = cleaned.replace("-", "").replace("_", "")
200
+
201
+ if lower:
202
+ cleaned = cleaned.lower()
203
+
204
+ return cleaned
205
+
206
+ def generate_batch(
207
+ self,
208
+ length: int = 16,
209
+ type: str = "normal",
210
+ count: int = 1,
211
+ lower: bool = False,
212
+ no_separator: bool = False,
213
+ ) -> list[str]:
214
+ if count <= 0:
215
+ raise ValueError("count must be a positive integer")
216
+
217
+ return [
218
+ self.generate_password(length=length, type=type, lower=lower, no_separator=no_separator)
219
+ for _ in range(count)
220
+ ]
221
+
222
+
223
+ clinkey = Clinkey()
224
+
225
+ __all__ = ["Clinkey", "clinkey"]
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: clinkey-cli
3
+ Version: 1.0.0
4
+ Summary: A command-line tool for generating strong passwords and secret keys.
5
+ Author: Clinkey
6
+ License-Expression: MIT
7
+ Keywords: password,cli,security
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Environment :: Console
11
+ Classifier: Topic :: Security
12
+ Classifier: Topic :: Utilities
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: click>=8.1.0
17
+ Requires-Dist: rich>=13.0.0
18
+ Dynamic: license-file
19
+
20
+ ![](clinkey_preview.png)
21
+
22
+ ---
23
+ ```bash
24
+ Your password generator *'buddy'*, available on a CLI.
25
+ ```
26
+ ---
27
+ ```bash
28
+ Usage python3 heat.py clinkey [OPTIONS]
29
+ ```
30
+ ---
31
+ ```bash
32
+ -l, --length The desired length for the output password(s)
33
+ -n, --number The amount of password you are expecting from ClinKey to generate.
34
+ -o, --output The path of a file in which to print the result instead of echoing it into the Terminal.
35
+ -t --type The strength and complexity of the password content.
36
+ Possible values:
37
+ - 'normal' - Containing only alphabetical characters.
38
+ - 'strong' - Mixing letters and digits.
39
+ - 'super_strong' - Adding special characters to the result.
40
+ -ns, --no-sep Clear the result from the hyphens used to separate the groups of letters usually forming the result.
41
+ -low, --lower Transform the output password in lowercase string.
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ clinkey_cli/__init__.py
5
+ clinkey_cli/cli.py
6
+ clinkey_cli/main.py
7
+ clinkey_cli.egg-info/PKG-INFO
8
+ clinkey_cli.egg-info/SOURCES.txt
9
+ clinkey_cli.egg-info/dependency_links.txt
10
+ clinkey_cli.egg-info/entry_points.txt
11
+ clinkey_cli.egg-info/requires.txt
12
+ clinkey_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ clinkey = clinkey_cli.cli:main
@@ -0,0 +1,2 @@
1
+ click>=8.1.0
2
+ rich>=13.0.0
@@ -0,0 +1 @@
1
+ clinkey_cli
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=66", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "clinkey-cli"
7
+ version = "1.0.0"
8
+ description = "A command-line tool for generating strong passwords and secret keys."
9
+ readme = "README.md"
10
+ requires-python = ">=3.7"
11
+ license = "MIT"
12
+ authors = [{name = "Clinkey"}]
13
+ keywords = ["password", "cli", "security"]
14
+ # J'ai ajouté des "classifiers" pour une meilleure visibilité sur PyPI
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ "Environment :: Console",
19
+ "Topic :: Security",
20
+ "Topic :: Utilities",
21
+ ]
22
+ dependencies = [
23
+ "click>=8.1.0",
24
+ "rich>=13.0.0",
25
+ ]
26
+
27
+ [project.scripts]
28
+ clinkey = "clinkey_cli.cli:main"
29
+
30
+ [tool.setuptools.packages.find]
31
+ where = ["."]
32
+ include = ["clinkey_cli*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+