codecrate 0.1.0__py3-none-any.whl → 0.1.2__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.
Potentially problematic release.
This version of codecrate might be problematic. Click here for more details.
- codecrate/_version.py +2 -2
- codecrate/cli.py +238 -55
- codecrate/config.py +13 -4
- codecrate/parse.py +3 -1
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/METADATA +1 -1
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/RECORD +10 -10
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/WHEEL +1 -1
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/entry_points.txt +0 -0
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {codecrate-0.1.0.dist-info → codecrate-0.1.2.dist-info}/top_level.txt +0 -0
codecrate/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.2'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 2)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
codecrate/cli.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
from dataclasses import dataclass
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
|
-
from .config import load_config
|
|
7
|
+
from .config import Config, load_config
|
|
7
8
|
from .diffgen import generate_patch_markdown
|
|
8
9
|
from .discover import discover_files
|
|
9
10
|
from .markdown import render_markdown
|
|
@@ -22,8 +23,22 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
22
23
|
sub = p.add_subparsers(dest="cmd", required=True)
|
|
23
24
|
|
|
24
25
|
# pack
|
|
25
|
-
pack = sub.add_parser(
|
|
26
|
-
|
|
26
|
+
pack = sub.add_parser(
|
|
27
|
+
"pack", help="Pack one or more repositories/directories into Markdown."
|
|
28
|
+
)
|
|
29
|
+
pack.add_argument(
|
|
30
|
+
"root",
|
|
31
|
+
type=Path,
|
|
32
|
+
nargs="?",
|
|
33
|
+
help="Root directory to scan (omit when using --repo)",
|
|
34
|
+
)
|
|
35
|
+
pack.add_argument(
|
|
36
|
+
"--repo",
|
|
37
|
+
action="append",
|
|
38
|
+
default=None,
|
|
39
|
+
type=Path,
|
|
40
|
+
help="Additional repo root to pack (repeatable; use instead of ROOT)",
|
|
41
|
+
)
|
|
27
42
|
pack.add_argument(
|
|
28
43
|
"-o",
|
|
29
44
|
"--output",
|
|
@@ -123,6 +138,135 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
123
138
|
return p
|
|
124
139
|
|
|
125
140
|
|
|
141
|
+
@dataclass(frozen=True)
|
|
142
|
+
class PackOptions:
|
|
143
|
+
include: list[str] | None
|
|
144
|
+
exclude: list[str] | None
|
|
145
|
+
keep_docstrings: bool
|
|
146
|
+
include_manifest: bool
|
|
147
|
+
respect_gitignore: bool
|
|
148
|
+
dedupe: bool
|
|
149
|
+
split_max_chars: int
|
|
150
|
+
layout: str
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@dataclass(frozen=True)
|
|
154
|
+
class PackRun:
|
|
155
|
+
root: Path
|
|
156
|
+
label: str
|
|
157
|
+
slug: str
|
|
158
|
+
markdown: str
|
|
159
|
+
options: PackOptions
|
|
160
|
+
default_output: Path
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _resolve_pack_options(cfg: Config, args: argparse.Namespace) -> PackOptions:
|
|
164
|
+
include = args.include if args.include is not None else cfg.include
|
|
165
|
+
exclude = args.exclude if args.exclude is not None else cfg.exclude
|
|
166
|
+
keep_docstrings = (
|
|
167
|
+
cfg.keep_docstrings
|
|
168
|
+
if args.keep_docstrings is None
|
|
169
|
+
else bool(args.keep_docstrings)
|
|
170
|
+
)
|
|
171
|
+
include_manifest = cfg.manifest if args.manifest is None else bool(args.manifest)
|
|
172
|
+
respect_gitignore = (
|
|
173
|
+
cfg.respect_gitignore
|
|
174
|
+
if args.respect_gitignore is None
|
|
175
|
+
else bool(args.respect_gitignore)
|
|
176
|
+
)
|
|
177
|
+
dedupe = bool(args.dedupe) or bool(cfg.dedupe)
|
|
178
|
+
split_max_chars = (
|
|
179
|
+
cfg.split_max_chars
|
|
180
|
+
if args.split_max_chars is None
|
|
181
|
+
else int(args.split_max_chars or 0)
|
|
182
|
+
)
|
|
183
|
+
layout = (
|
|
184
|
+
str(args.layout).strip().lower()
|
|
185
|
+
if args.layout is not None
|
|
186
|
+
else str(getattr(cfg, "layout", "auto")).strip().lower()
|
|
187
|
+
)
|
|
188
|
+
return PackOptions(
|
|
189
|
+
include=include,
|
|
190
|
+
exclude=exclude,
|
|
191
|
+
keep_docstrings=keep_docstrings,
|
|
192
|
+
include_manifest=include_manifest,
|
|
193
|
+
respect_gitignore=respect_gitignore,
|
|
194
|
+
dedupe=dedupe,
|
|
195
|
+
split_max_chars=split_max_chars,
|
|
196
|
+
layout=layout,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _resolve_output_path(cfg: Config, args: argparse.Namespace, root: Path) -> Path:
|
|
201
|
+
if args.output is not None:
|
|
202
|
+
return args.output
|
|
203
|
+
out_path = Path(getattr(cfg, "output", "context.md"))
|
|
204
|
+
if not out_path.is_absolute():
|
|
205
|
+
out_path = root / out_path
|
|
206
|
+
return out_path
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _default_repo_label(root: Path) -> str:
|
|
210
|
+
cwd = Path.cwd().resolve()
|
|
211
|
+
resolved = root.resolve()
|
|
212
|
+
try:
|
|
213
|
+
rel = resolved.relative_to(cwd).as_posix()
|
|
214
|
+
return rel or resolved.name or resolved.as_posix()
|
|
215
|
+
except ValueError:
|
|
216
|
+
return root.name or resolved.name or resolved.as_posix()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _unique_label(root: Path, used: set[str]) -> str:
|
|
220
|
+
base = _default_repo_label(root)
|
|
221
|
+
label = base
|
|
222
|
+
idx = 2
|
|
223
|
+
while label in used:
|
|
224
|
+
label = f"{base}-{idx}"
|
|
225
|
+
idx += 1
|
|
226
|
+
used.add(label)
|
|
227
|
+
return label
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _slugify(label: str) -> str:
|
|
231
|
+
safe: list[str] = []
|
|
232
|
+
for ch in label:
|
|
233
|
+
if ch.isalnum() or ch in {"-", "_"}:
|
|
234
|
+
safe.append(ch)
|
|
235
|
+
else:
|
|
236
|
+
safe.append("-")
|
|
237
|
+
slug = "".join(safe).strip("-")
|
|
238
|
+
while "--" in slug:
|
|
239
|
+
slug = slug.replace("--", "-")
|
|
240
|
+
return slug or "repo"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _unique_slug(label: str, used: set[str]) -> str:
|
|
244
|
+
base = _slugify(label)
|
|
245
|
+
slug = base
|
|
246
|
+
idx = 2
|
|
247
|
+
while slug in used:
|
|
248
|
+
slug = f"{base}-{idx}"
|
|
249
|
+
idx += 1
|
|
250
|
+
used.add(slug)
|
|
251
|
+
return slug
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _prefix_repo_header(text: str, label: str) -> str:
|
|
255
|
+
header = f"# Repository: {label}\n\n"
|
|
256
|
+
if text.startswith(header):
|
|
257
|
+
return text
|
|
258
|
+
return header + text
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _combine_pack_markdown(packs: list[PackRun]) -> str:
|
|
262
|
+
out: list[str] = []
|
|
263
|
+
for i, pack in enumerate(packs):
|
|
264
|
+
if i:
|
|
265
|
+
out.append("\n\n")
|
|
266
|
+
out.append(_prefix_repo_header(pack.markdown.rstrip() + "\n", pack.label))
|
|
267
|
+
return "".join(out).rstrip() + "\n"
|
|
268
|
+
|
|
269
|
+
|
|
126
270
|
def _extract_diff_blocks(md_text: str) -> str:
|
|
127
271
|
"""
|
|
128
272
|
Extract only diff fences from markdown and concatenate to a unified diff string.
|
|
@@ -140,72 +284,111 @@ def _extract_diff_blocks(md_text: str) -> str:
|
|
|
140
284
|
return "\n".join(out) + "\n"
|
|
141
285
|
|
|
142
286
|
|
|
143
|
-
def main(argv: list[str] | None = None) -> None:
|
|
287
|
+
def main(argv: list[str] | None = None) -> None: # noqa: C901
|
|
144
288
|
parser = build_parser()
|
|
145
289
|
args = parser.parse_args(argv)
|
|
146
290
|
|
|
147
291
|
if args.cmd == "pack":
|
|
148
|
-
|
|
149
|
-
|
|
292
|
+
if args.repo:
|
|
293
|
+
if args.root is not None:
|
|
294
|
+
parser.error(
|
|
295
|
+
"pack: specify either ROOT or --repo (repeatable), not both"
|
|
296
|
+
)
|
|
297
|
+
roots = [r.resolve() for r in args.repo]
|
|
298
|
+
else:
|
|
299
|
+
if args.root is None:
|
|
300
|
+
parser.error("pack: ROOT is required when --repo is not used")
|
|
301
|
+
roots = [args.root.resolve()]
|
|
150
302
|
|
|
151
|
-
|
|
152
|
-
|
|
303
|
+
used_labels: set[str] = set()
|
|
304
|
+
used_slugs: set[str] = set()
|
|
305
|
+
pack_runs: list[PackRun] = []
|
|
306
|
+
|
|
307
|
+
for root in roots:
|
|
308
|
+
cfg = load_config(root)
|
|
309
|
+
options = _resolve_pack_options(cfg, args)
|
|
310
|
+
label = _unique_label(root, used_labels)
|
|
311
|
+
slug = _unique_slug(label, used_slugs)
|
|
312
|
+
|
|
313
|
+
disc = discover_files(
|
|
314
|
+
root=root,
|
|
315
|
+
include=options.include,
|
|
316
|
+
exclude=options.exclude,
|
|
317
|
+
respect_gitignore=options.respect_gitignore,
|
|
318
|
+
)
|
|
319
|
+
pack, canonical = pack_repo(
|
|
320
|
+
disc.root,
|
|
321
|
+
disc.files,
|
|
322
|
+
keep_docstrings=options.keep_docstrings,
|
|
323
|
+
dedupe=options.dedupe,
|
|
324
|
+
)
|
|
325
|
+
md = render_markdown(
|
|
326
|
+
pack,
|
|
327
|
+
canonical,
|
|
328
|
+
layout=options.layout,
|
|
329
|
+
include_manifest=options.include_manifest,
|
|
330
|
+
)
|
|
331
|
+
default_output = _resolve_output_path(cfg, args, root)
|
|
332
|
+
pack_runs.append(
|
|
333
|
+
PackRun(
|
|
334
|
+
root=root,
|
|
335
|
+
label=label,
|
|
336
|
+
slug=slug,
|
|
337
|
+
markdown=md,
|
|
338
|
+
options=options,
|
|
339
|
+
default_output=default_output,
|
|
340
|
+
)
|
|
341
|
+
)
|
|
153
342
|
|
|
154
|
-
keep_docstrings = (
|
|
155
|
-
cfg.keep_docstrings
|
|
156
|
-
if args.keep_docstrings is None
|
|
157
|
-
else bool(args.keep_docstrings)
|
|
158
|
-
)
|
|
159
|
-
include_manifest = (
|
|
160
|
-
cfg.manifest if args.manifest is None else bool(args.manifest)
|
|
161
|
-
)
|
|
162
|
-
respect_gitignore = (
|
|
163
|
-
cfg.respect_gitignore
|
|
164
|
-
if args.respect_gitignore is None
|
|
165
|
-
else bool(args.respect_gitignore)
|
|
166
|
-
)
|
|
167
|
-
dedupe = bool(args.dedupe) or bool(cfg.dedupe)
|
|
168
|
-
split_max_chars = (
|
|
169
|
-
cfg.split_max_chars
|
|
170
|
-
if args.split_max_chars is None
|
|
171
|
-
else int(args.split_max_chars or 0)
|
|
172
|
-
)
|
|
173
|
-
layout = (
|
|
174
|
-
str(args.layout).strip().lower()
|
|
175
|
-
if args.layout is not None
|
|
176
|
-
else str(getattr(cfg, "layout", "auto")).strip().lower()
|
|
177
|
-
)
|
|
178
343
|
out_path = (
|
|
179
|
-
args.output
|
|
180
|
-
if args.output is not None
|
|
181
|
-
else Path(getattr(cfg, "output", "context.md"))
|
|
182
|
-
)
|
|
183
|
-
disc = discover_files(
|
|
184
|
-
root=root,
|
|
185
|
-
include=include,
|
|
186
|
-
exclude=exclude,
|
|
187
|
-
respect_gitignore=respect_gitignore,
|
|
188
|
-
)
|
|
189
|
-
pack, canonical = pack_repo(
|
|
190
|
-
disc.root, disc.files, keep_docstrings=keep_docstrings, dedupe=dedupe
|
|
191
|
-
)
|
|
192
|
-
md = render_markdown(
|
|
193
|
-
pack, canonical, layout=layout, include_manifest=include_manifest
|
|
344
|
+
args.output if args.output is not None else pack_runs[0].default_output
|
|
194
345
|
)
|
|
346
|
+
if len(pack_runs) == 1:
|
|
347
|
+
md = pack_runs[0].markdown
|
|
348
|
+
else:
|
|
349
|
+
md = _combine_pack_markdown(pack_runs)
|
|
350
|
+
|
|
195
351
|
# Always write the canonical, unsplit pack
|
|
196
352
|
# for machine parsing (unpack/validate).
|
|
197
353
|
out_path.write_text(md, encoding="utf-8")
|
|
198
354
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
355
|
+
extra_count = 0
|
|
356
|
+
if len(pack_runs) == 1:
|
|
357
|
+
split_max_chars = pack_runs[0].options.split_max_chars
|
|
358
|
+
parts = split_by_max_chars(md, out_path, split_max_chars)
|
|
359
|
+
extra = [p for p in parts if p.path != out_path]
|
|
360
|
+
for part in extra:
|
|
361
|
+
part.path.write_text(part.content, encoding="utf-8")
|
|
362
|
+
extra_count += len(extra)
|
|
363
|
+
else:
|
|
364
|
+
for pack in pack_runs:
|
|
365
|
+
if pack.options.split_max_chars <= 0:
|
|
366
|
+
continue
|
|
367
|
+
repo_base = out_path.with_name(
|
|
368
|
+
f"{out_path.stem}.{pack.slug}{out_path.suffix}"
|
|
369
|
+
)
|
|
370
|
+
parts = split_by_max_chars(
|
|
371
|
+
pack.markdown, repo_base, pack.options.split_max_chars
|
|
372
|
+
)
|
|
373
|
+
extra = [p for p in parts if p.path != repo_base]
|
|
374
|
+
for part in extra:
|
|
375
|
+
content = _prefix_repo_header(part.content, pack.label)
|
|
376
|
+
part.path.write_text(content, encoding="utf-8")
|
|
377
|
+
extra_count += len(extra)
|
|
204
378
|
|
|
205
|
-
if
|
|
206
|
-
|
|
379
|
+
if extra_count:
|
|
380
|
+
if len(pack_runs) == 1:
|
|
381
|
+
print(f"Wrote {out_path} and {extra_count} split part file(s).")
|
|
382
|
+
else:
|
|
383
|
+
print(
|
|
384
|
+
f"Wrote {out_path} and {extra_count} split part file(s) for "
|
|
385
|
+
f"{len(pack_runs)} repos."
|
|
386
|
+
)
|
|
207
387
|
else:
|
|
208
|
-
|
|
388
|
+
if len(pack_runs) == 1:
|
|
389
|
+
print(f"Wrote {out_path}.")
|
|
390
|
+
else:
|
|
391
|
+
print(f"Wrote {out_path} for {len(pack_runs)} repos.")
|
|
209
392
|
elif args.cmd == "unpack":
|
|
210
393
|
md_text = args.markdown.read_text(encoding="utf-8", errors="replace")
|
|
211
394
|
unpack_to_dir(md_text, args.out_dir)
|
codecrate/config.py
CHANGED
|
@@ -61,10 +61,19 @@ def load_config(root: Path) -> Config:
|
|
|
61
61
|
return Config()
|
|
62
62
|
|
|
63
63
|
data = tomllib.loads(cfg_path.read_text(encoding="utf-8"))
|
|
64
|
-
section: dict[str, Any] =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
section: dict[str, Any] = {}
|
|
65
|
+
if isinstance(data, dict):
|
|
66
|
+
# Preferred: [codecrate]
|
|
67
|
+
cc = data.get("codecrate")
|
|
68
|
+
if isinstance(cc, dict):
|
|
69
|
+
section = cc
|
|
70
|
+
else:
|
|
71
|
+
# Also accept: [tool.codecrate] (common convention from pyproject.toml)
|
|
72
|
+
tool = data.get("tool")
|
|
73
|
+
if isinstance(tool, dict):
|
|
74
|
+
cc2 = tool.get("codecrate")
|
|
75
|
+
if isinstance(cc2, dict):
|
|
76
|
+
section = cc2
|
|
68
77
|
cfg = Config()
|
|
69
78
|
out = section.get("output", cfg.output)
|
|
70
79
|
if isinstance(out, str) and out.strip():
|
codecrate/parse.py
CHANGED
|
@@ -127,7 +127,9 @@ class _Visitor(ast.NodeVisitor):
|
|
|
127
127
|
def parse_symbols(
|
|
128
128
|
path: Path, root: Path, text: str
|
|
129
129
|
) -> tuple[list[ClassRef], list[DefRef]]:
|
|
130
|
-
|
|
130
|
+
# Pass filename so SyntaxWarnings (e.g. invalid escape sequences) point to
|
|
131
|
+
# the real file instead of "<unknown>".
|
|
132
|
+
tree = ast.parse(text, filename=path.as_posix())
|
|
131
133
|
v = _Visitor(path=path, root=root)
|
|
132
134
|
v.visit(tree)
|
|
133
135
|
return v.classes, v.defs
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
codecrate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
codecrate/_version.py,sha256=
|
|
3
|
-
codecrate/cli.py,sha256=
|
|
4
|
-
codecrate/config.py,sha256=
|
|
2
|
+
codecrate/_version.py,sha256=Ok5oAXdWgR9aghaFXTafTeDW6sYO3uVe6d2Nket57R4,704
|
|
3
|
+
codecrate/cli.py,sha256=AXURc8QeFzR0HvbhittK38g4N1xr4al564uCBq0PTlY,13644
|
|
4
|
+
codecrate/config.py,sha256=8VOmpjHC3am6LRFnyHUY3376947XTvSFGp3fUxSZgOk,3523
|
|
5
5
|
codecrate/diffgen.py,sha256=xMH-wJeMox_xoMLrGck2o7RP5mjlCJjndSHPHql9CJg,3432
|
|
6
6
|
codecrate/discover.py,sha256=eWebPPbPHy5WrtbCX-RA1hKiPyQau6buUm5OcjpVi9U,2847
|
|
7
7
|
codecrate/ids.py,sha256=fO_PAaskT7hLXgvJN7Hv4HD27zPIFnSziB0k2AUpONo,517
|
|
@@ -10,15 +10,15 @@ codecrate/markdown.py,sha256=2ruEmsCF9v-aPpiKEOGusi4T13wEzugNn7JSN6T7KGg,16670
|
|
|
10
10
|
codecrate/mdparse.py,sha256=Lu9aN3rMP5qetwLapVrRvVRohPXv8L0hmjG0GUG7jys,4746
|
|
11
11
|
codecrate/model.py,sha256=Px9xL4odcvlDgEnSiwd5SMi9_k1Xck4R8DOlahN9Z-4,897
|
|
12
12
|
codecrate/packer.py,sha256=an-E1ZilIOY2hdjF4Gt3J5APOCTRRpiinmvfBiw29Ds,3398
|
|
13
|
-
codecrate/parse.py,sha256=
|
|
13
|
+
codecrate/parse.py,sha256=7baMIxRQoZGNAgFsydalC6cYZGRqDF4KWz8qhpzLDRw,4586
|
|
14
14
|
codecrate/stubber.py,sha256=9WxpQs6FTCT0OUX4Si8GdD63VyUJQnNqRcwTm_IPuKc,2857
|
|
15
15
|
codecrate/token_budget.py,sha256=0vG9h7l5yNn909QQEItrYQJIjMT2h5LcM9iZf4zu-3c,12937
|
|
16
16
|
codecrate/udiff.py,sha256=bMvwhgqXZw2pIW5VcRRATUoDspM2XGQU3nInD_A7WWo,6249
|
|
17
17
|
codecrate/unpacker.py,sha256=soh6qwRE6sxoBAbr3UbXk1O5aiwdnfUhkqfFdSvU0_I,5063
|
|
18
18
|
codecrate/validate.py,sha256=-KVU7RQ8zJG-YJoD8kLCYgE0OWWdy-yYzl0gyp-3mWo,4250
|
|
19
|
-
codecrate-0.1.
|
|
20
|
-
codecrate-0.1.
|
|
21
|
-
codecrate-0.1.
|
|
22
|
-
codecrate-0.1.
|
|
23
|
-
codecrate-0.1.
|
|
24
|
-
codecrate-0.1.
|
|
19
|
+
codecrate-0.1.2.dist-info/licenses/LICENSE,sha256=O6yVC2oL8vUoAA3oPEvLSbvxzmwtOOPiY7dOZzgrxi0,1074
|
|
20
|
+
codecrate-0.1.2.dist-info/METADATA,sha256=9GAqz6NFaQ1g9uRKKYw6hn4RVhmO5lemKle54PVDoK4,9394
|
|
21
|
+
codecrate-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
22
|
+
codecrate-0.1.2.dist-info/entry_points.txt,sha256=DcY9tib-PzdLebck4B2RYJ0CGH6cqAJMCHPU3MdA0Dk,49
|
|
23
|
+
codecrate-0.1.2.dist-info/top_level.txt,sha256=-jD2a_aH1iQN4atRhGw7ZhEYnOWe88nfmkz6sPZ6WEg,10
|
|
24
|
+
codecrate-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|