context-engineering-cli 2.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.
Files changed (55) hide show
  1. context_engineering/__init__.py +3 -0
  2. context_engineering/__main__.py +2 -0
  3. context_engineering/analysis/__init__.py +1 -0
  4. context_engineering/analysis/backfill.py +1064 -0
  5. context_engineering/analysis/context_check.py +253 -0
  6. context_engineering/analysis/context_layout.py +111 -0
  7. context_engineering/analysis/context_review.py +224 -0
  8. context_engineering/analysis/cross_cutting/__init__.py +6 -0
  9. context_engineering/analysis/cross_cutting/authors.py +57 -0
  10. context_engineering/analysis/cross_cutting/buckets.py +40 -0
  11. context_engineering/analysis/cross_cutting/co_change.py +47 -0
  12. context_engineering/analysis/cross_cutting/discover.py +75 -0
  13. context_engineering/analysis/cross_cutting/imports.py +61 -0
  14. context_engineering/analysis/cross_cutting/pair.py +118 -0
  15. context_engineering/analysis/impact.py +77 -0
  16. context_engineering/analysis/sessions.py +27 -0
  17. context_engineering/analysis/staleness.py +179 -0
  18. context_engineering/analysis/tier.py +91 -0
  19. context_engineering/checks/__init__.py +1 -0
  20. context_engineering/checks/antipatterns/__init__.py +5 -0
  21. context_engineering/checks/antipatterns/context.py +23 -0
  22. context_engineering/checks/antipatterns/density.py +72 -0
  23. context_engineering/checks/antipatterns/line_limits.py +52 -0
  24. context_engineering/checks/antipatterns/runner.py +137 -0
  25. context_engineering/checks/antipatterns/splitting.py +97 -0
  26. context_engineering/checks/antipatterns/volatile.py +38 -0
  27. context_engineering/checks/antipatterns/watermark.py +113 -0
  28. context_engineering/checks/contracts.py +456 -0
  29. context_engineering/checks/depth.py +82 -0
  30. context_engineering/checks/frontmatter.py +125 -0
  31. context_engineering/checks/references.py +325 -0
  32. context_engineering/checks/skill_structure.py +124 -0
  33. context_engineering/cli/__init__.py +3 -0
  34. context_engineering/cli/dispatch.py +90 -0
  35. context_engineering/cli/registry.py +33 -0
  36. context_engineering/cli/render.py +92 -0
  37. context_engineering/cli/subcommands.py +587 -0
  38. context_engineering/domain/__init__.py +0 -0
  39. context_engineering/domain/commit.py +19 -0
  40. context_engineering/domain/evidence.py +57 -0
  41. context_engineering/domain/finding.py +37 -0
  42. context_engineering/domain/result.py +59 -0
  43. context_engineering/infra/__init__.py +13 -0
  44. context_engineering/infra/filesystem.py +22 -0
  45. context_engineering/infra/git.py +153 -0
  46. context_engineering/infra/git_evidence.py +357 -0
  47. context_engineering/infra/git_tree.py +139 -0
  48. context_engineering/infra/markdown.py +58 -0
  49. context_engineering/infra/yaml_frontmatter.py +70 -0
  50. context_engineering_cli-2.6.0.dist-info/METADATA +27 -0
  51. context_engineering_cli-2.6.0.dist-info/RECORD +55 -0
  52. context_engineering_cli-2.6.0.dist-info/WHEEL +4 -0
  53. context_engineering_cli-2.6.0.dist-info/entry_points.txt +2 -0
  54. context_engineering_cli-2.6.0.dist-info/licenses/LICENSE +21 -0
  55. provenance.json +1 -0
@@ -0,0 +1,139 @@
1
+ """Read an exact Git tree through a temporary, disposable filesystem view."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import posixpath
7
+ import stat
8
+ import subprocess
9
+ from collections.abc import Iterator
10
+ from contextlib import contextmanager
11
+ from dataclasses import dataclass
12
+ from pathlib import Path, PurePosixPath
13
+ from tempfile import TemporaryDirectory
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class _TreeEntry:
18
+ mode: str
19
+ object_id: str
20
+ path: str
21
+
22
+
23
+ def _tree_entries(repo: Path, commit: str) -> tuple[list[_TreeEntry], str | None]:
24
+ try:
25
+ result = subprocess.run(
26
+ ["git", "ls-tree", "-r", "-z", "--full-tree", commit],
27
+ cwd=repo,
28
+ capture_output=True,
29
+ check=False,
30
+ timeout=120,
31
+ )
32
+ except (OSError, subprocess.TimeoutExpired) as exc:
33
+ return [], f"could not read Git tree: {exc}"
34
+ if result.returncode != 0:
35
+ message = os.fsdecode(result.stderr).strip() or "git ls-tree failed"
36
+ return [], message
37
+ entries: list[_TreeEntry] = []
38
+ for record in result.stdout.split(b"\0"):
39
+ if not record:
40
+ continue
41
+ metadata, separator, raw_path = record.partition(b"\t")
42
+ fields = metadata.split()
43
+ if not separator or len(fields) != 3:
44
+ return [], "git ls-tree returned a malformed record"
45
+ mode, object_type, object_id = (os.fsdecode(field) for field in fields)
46
+ path = os.fsdecode(raw_path)
47
+ pure = PurePosixPath(path)
48
+ if pure.is_absolute() or any(part in {"", ".", ".."} for part in pure.parts):
49
+ return [], f"git tree contains an unsafe path: {path!r}"
50
+ if object_type == "blob":
51
+ entries.append(_TreeEntry(mode=mode, object_id=object_id, path=path))
52
+ elif mode == "160000":
53
+ entries.append(_TreeEntry(mode=mode, object_id=object_id, path=path))
54
+ return entries, None
55
+
56
+
57
+ def _read_blobs(
58
+ repo: Path, entries: list[_TreeEntry]
59
+ ) -> tuple[dict[str, bytes], str | None]:
60
+ object_ids = list(dict.fromkeys(entry.object_id for entry in entries if entry.mode != "160000"))
61
+ if not object_ids:
62
+ return {}, None
63
+ try:
64
+ result = subprocess.run(
65
+ ["git", "cat-file", "--batch"],
66
+ cwd=repo,
67
+ input=("\n".join(object_ids) + "\n").encode(),
68
+ capture_output=True,
69
+ check=False,
70
+ timeout=120,
71
+ )
72
+ except (OSError, subprocess.TimeoutExpired) as exc:
73
+ return {}, f"could not read Git blobs: {exc}"
74
+ if result.returncode != 0:
75
+ message = os.fsdecode(result.stderr).strip() or "git cat-file failed"
76
+ return {}, message
77
+ blobs: dict[str, bytes] = {}
78
+ output = result.stdout
79
+ offset = 0
80
+ for expected in object_ids:
81
+ newline = output.find(b"\n", offset)
82
+ if newline < 0:
83
+ return {}, "git cat-file returned a truncated header"
84
+ fields = output[offset:newline].split()
85
+ if len(fields) != 3 or os.fsdecode(fields[0]) != expected or fields[1] != b"blob":
86
+ return {}, "git cat-file returned unexpected object metadata"
87
+ try:
88
+ size = int(fields[2])
89
+ except ValueError:
90
+ return {}, "git cat-file returned an invalid blob size"
91
+ start = newline + 1
92
+ end = start + size
93
+ if end >= len(output) or output[end : end + 1] != b"\n":
94
+ return {}, "git cat-file returned truncated blob content"
95
+ blobs[expected] = output[start:end]
96
+ offset = end + 1
97
+ if offset != len(output):
98
+ return {}, "git cat-file returned trailing data"
99
+ return blobs, None
100
+
101
+
102
+ @contextmanager
103
+ def materialize_tree(repo: Path, commit: str) -> Iterator[tuple[Path | None, str | None]]:
104
+ """Yield tracked tree bytes without checkout filters or archive attributes."""
105
+ entries, entry_error = _tree_entries(repo, commit)
106
+ if entry_error:
107
+ yield None, entry_error
108
+ return
109
+ blobs, blob_error = _read_blobs(repo, entries)
110
+ if blob_error:
111
+ yield None, blob_error
112
+ return
113
+ with TemporaryDirectory(prefix="context-engineering-tree-") as temporary:
114
+ root = Path(temporary)
115
+ try:
116
+ for entry in entries:
117
+ target = root.joinpath(*PurePosixPath(entry.path).parts)
118
+ if entry.mode == "160000":
119
+ target.mkdir(parents=True, exist_ok=True)
120
+ continue
121
+ target.parent.mkdir(parents=True, exist_ok=True)
122
+ content = blobs[entry.object_id]
123
+ if entry.mode == "120000":
124
+ link_text = os.fsdecode(content)
125
+ link = PurePosixPath(link_text)
126
+ normalized = posixpath.normpath(
127
+ str(PurePosixPath(entry.path).parent / link)
128
+ )
129
+ if link.is_absolute() or normalized == ".." or normalized.startswith("../"):
130
+ raise OSError(f"tracked symlink escapes the Git tree: {entry.path!r}")
131
+ target.symlink_to(link_text)
132
+ continue
133
+ target.write_bytes(content)
134
+ if entry.mode == "100755":
135
+ target.chmod(target.stat().st_mode | stat.S_IXUSR)
136
+ except OSError as exc:
137
+ yield None, f"could not materialize Git tree: {exc}"
138
+ return
139
+ yield root, None
@@ -0,0 +1,58 @@
1
+ """Shared Markdown visibility helpers for deterministic context checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+
7
+ _HTML_COMMENT_RE = re.compile(r"<!--.*?(?:-->|$)", re.DOTALL)
8
+
9
+
10
+ def _masked_line(line: str) -> str:
11
+ return "".join(
12
+ "\n" if character == "\n" else "\r" if character == "\r" else " " for character in line
13
+ )
14
+
15
+
16
+ def _fence_marker(line: str) -> tuple[str, int] | None:
17
+ text = line.rstrip("\r\n")
18
+ indentation = len(text) - len(text.lstrip(" "))
19
+ if indentation > 3:
20
+ return None
21
+ body = text[indentation:]
22
+ if not body or body[0] not in {"`", "~"}:
23
+ return None
24
+ marker = body[0]
25
+ length = len(body) - len(body.lstrip(marker))
26
+ return (marker, length) if length >= 3 else None
27
+
28
+
29
+ def _closes_fence(line: str, marker: str, minimum_length: int) -> bool:
30
+ text = line.rstrip("\r\n")
31
+ indentation = len(text) - len(text.lstrip(" "))
32
+ if indentation > 3:
33
+ return False
34
+ body = text[indentation:]
35
+ length = len(body) - len(body.lstrip(marker))
36
+ return length >= minimum_length and not body[length:].strip()
37
+
38
+
39
+ def mask_invisible_markdown(content: str) -> str:
40
+ """Replace fenced blocks and HTML comments while preserving line positions."""
41
+ visible: list[str] = []
42
+ marker: str | None = None
43
+ minimum_length = 0
44
+ for line in content.splitlines(keepends=True):
45
+ if marker is not None:
46
+ visible.append(_masked_line(line))
47
+ if _closes_fence(line, marker, minimum_length):
48
+ marker = None
49
+ minimum_length = 0
50
+ continue
51
+ opening = _fence_marker(line)
52
+ if opening is None:
53
+ visible.append(line)
54
+ continue
55
+ marker, minimum_length = opening
56
+ visible.append(_masked_line(line))
57
+ without_fences = "".join(visible)
58
+ return _HTML_COMMENT_RE.sub(lambda match: _masked_line(match.group(0)), without_fences)
@@ -0,0 +1,70 @@
1
+ """One frontmatter parser. Replaces the two hand-rolled parsers in the codebase.
2
+
3
+ We don't pull in PyYAML — the schema is tightly constrained (kebab-cased top-level
4
+ keys, optional scalar values, optional list of inline dicts). This parser handles
5
+ everything the plugin emits and nothing more.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+
12
+ _TOP_KEY_RE = re.compile(r"^([a-z][a-z0-9_-]*):\s*(.*)$")
13
+
14
+
15
+ def parse_frontmatter(content: str) -> tuple[dict | None, str]:
16
+ """Return (frontmatter_dict, body). `None` if content has no frontmatter."""
17
+ if not content.startswith("---"):
18
+ return None, content
19
+
20
+ end = content.find("\n---", 3)
21
+ if end == -1:
22
+ return None, content
23
+
24
+ raw = content[3:end].strip()
25
+ body = content[end + 4:].lstrip("\n")
26
+
27
+ fm: dict = {}
28
+ current_key: str | None = None
29
+ current_list: list | None = None
30
+
31
+ for line in raw.splitlines():
32
+ if not line.strip() or line.strip().startswith("#"):
33
+ continue
34
+
35
+ top = _TOP_KEY_RE.match(line) if not line.startswith(" ") else None
36
+ if top:
37
+ if current_key is not None and current_list is not None:
38
+ fm[current_key] = current_list
39
+ current_list = None
40
+
41
+ key, value = top.group(1), top.group(2).strip()
42
+ if value == "":
43
+ current_key = key
44
+ current_list = None
45
+ elif value == "[]":
46
+ fm[key] = []
47
+ current_key = key
48
+ current_list = None
49
+ else:
50
+ fm[key] = value
51
+ current_key = key
52
+ current_list = None
53
+ continue
54
+
55
+ stripped = line.strip()
56
+ if stripped.startswith("- ") and current_key is not None:
57
+ item = stripped[2:].strip()
58
+ if current_list is None:
59
+ current_list = []
60
+ if ":" in item and item.split(":", 1)[0].strip().isidentifier():
61
+ # Inline dict entry like `- id: foo`
62
+ k, _, v = item.partition(":")
63
+ current_list.append({k.strip(): v.strip()})
64
+ else:
65
+ current_list.append(item)
66
+
67
+ if current_key is not None and current_list is not None:
68
+ fm[current_key] = current_list
69
+
70
+ return fm, body
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.5
2
+ Name: context-engineering-cli
3
+ Version: 2.6.0
4
+ Summary: Portable CLI for Context Engineering analyzers.
5
+ License: MIT License
6
+
7
+ Copyright (c) 2026 safurrier
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+ License-File: LICENSE
27
+ Requires-Python: >=3.11
@@ -0,0 +1,55 @@
1
+ context_engineering/__init__.py,sha256=3mgr87eJEJl9yhhFAzNPn6xHcy7EOov6KBuab6x3nU4,76
2
+ context_engineering/__main__.py,sha256=fi_tkPTbyCAM_UhTg1qcz10jmie3vNrg50QOOU4mX-s,75
3
+ context_engineering/analysis/__init__.py,sha256=1Sii4fbwxLJukSHqDYihcLV5fErPI6kRJumpa_rplNg,64
4
+ context_engineering/analysis/backfill.py,sha256=T7elnNsy7aeWpUPXAaQF5XRhh321tcZLv1sc8DczMDg,39108
5
+ context_engineering/analysis/context_check.py,sha256=lsjgMwyLUALlFc36T6Hsuwt3pND7fjEP8lbEbyuiSDo,9979
6
+ context_engineering/analysis/context_layout.py,sha256=MwZNgiEIUdhB9v92eyjskqMWYsCf2Y2i6zjf0027tco,3790
7
+ context_engineering/analysis/context_review.py,sha256=KFJG900geWdvovTpP28Y9JWYXMVi9XIRHsKvicA76zY,7501
8
+ context_engineering/analysis/impact.py,sha256=5f1_QCRdCklbVwQC1r3NlWJXXNPRp1twGPN1CdEgrhM,2736
9
+ context_engineering/analysis/sessions.py,sha256=NCjqN-xOY4dhktglcIQpxSWVoRFCHE_lVZEntCyNgWk,1439
10
+ context_engineering/analysis/staleness.py,sha256=HC3IVRlyu7e-S7vn3DzewFb8RWNpfZ8eyXQi36as85k,6153
11
+ context_engineering/analysis/tier.py,sha256=91ORWsJ_laQxUPI9JfQfBi0ygI31Jx7kRfX0LFCfU3g,2687
12
+ context_engineering/analysis/cross_cutting/__init__.py,sha256=RcDjy89T0zU2W-iI7fi1TJYf2pQOD_0Oo9BHlccMuMk,162
13
+ context_engineering/analysis/cross_cutting/authors.py,sha256=bYT1d1yZKT0qqM8d20_KC0lMlUOJkfT0igVovuv8mtk,1930
14
+ context_engineering/analysis/cross_cutting/buckets.py,sha256=3aqn-g0jK1MpejOfqE13cGwezOc5YEhBEwgg_qwJTYM,1354
15
+ context_engineering/analysis/cross_cutting/co_change.py,sha256=7tovGwRvI1I5mzuEXFWkEgLaCYeu9nDDqwAakbMr_gY,1591
16
+ context_engineering/analysis/cross_cutting/discover.py,sha256=uzNflqhI_8H__V7PLKlZFTB_ONm9VNZ41EK5_LIEVFQ,2507
17
+ context_engineering/analysis/cross_cutting/imports.py,sha256=kkZ8-uKqtTHbl1igS2kEe3eOeYWnyxqyNVVBZlOTCOU,2026
18
+ context_engineering/analysis/cross_cutting/pair.py,sha256=B91LFQ04EeTuffdtk8Kbfg4JalKsGNTXhEZZmkiElWg,4215
19
+ context_engineering/checks/__init__.py,sha256=G1oNPg6aUrqf9P70T7sBIC6W3xdWwJD8bJ5hXSO4Xcg,51
20
+ context_engineering/checks/contracts.py,sha256=B6EEWfZcAwAoHeolRiBjdOPebJqKmL_OB6VC5WWJgaQ,15631
21
+ context_engineering/checks/depth.py,sha256=sFY-42FvnvgunEwGgNRtQIca_MzgF1W3-cSu8V6-dyc,2963
22
+ context_engineering/checks/frontmatter.py,sha256=s1V5w75i7GwyZhLU7zladXdp_V804o3Z1Po38SBAFmU,4436
23
+ context_engineering/checks/references.py,sha256=28ZyXwHgCxxKC3BKDwbbo9QaYS98T9_UgJ6KrR7V44k,11370
24
+ context_engineering/checks/skill_structure.py,sha256=Tw97b3TnPQPNX_Wg91VvS8lkAeW97ianhEhwH7wKbQA,4513
25
+ context_engineering/checks/antipatterns/__init__.py,sha256=46H9dq5qr8T6sgDWY7V8r2Ayg2Gx_QoDXS_bGrgOow0,117
26
+ context_engineering/checks/antipatterns/context.py,sha256=_QklypUB9PJU0E86UC6GZnSCU_DJ03lzm9WZtMg4DeQ,675
27
+ context_engineering/checks/antipatterns/density.py,sha256=D9-zIoJUsReHPPV6DEB3CI3WeWf13vnolOpUNLESl1s,2206
28
+ context_engineering/checks/antipatterns/line_limits.py,sha256=WvH-H59NK6-XQ3xHaSCRbmrUpfYx2claOLsFQH4SzXk,1858
29
+ context_engineering/checks/antipatterns/runner.py,sha256=tY08CKqQ7d94RGI1d1i0XrQ4AnFdd6FRpiSKWmWBvqU,4206
30
+ context_engineering/checks/antipatterns/splitting.py,sha256=QJzV5Ut9dNP-RAHG4eT8wj6hItm1hlRFj6XrdqvowTs,3181
31
+ context_engineering/checks/antipatterns/volatile.py,sha256=8DLC591-dqf64FA-irI7QOA2c5IEwW0ANU60vWlu27w,1343
32
+ context_engineering/checks/antipatterns/watermark.py,sha256=fl4ESKBv8PPHNLM76ETDJydszTHgGhEK4oGQVwaJMl4,3753
33
+ context_engineering/cli/__init__.py,sha256=T8XCbwTmhRg-JFuhIqpiyRw-Dyba0SuaIOjYnzHq_T8,47
34
+ context_engineering/cli/dispatch.py,sha256=zParI8G6_QOHyk2baB0jDGMXGU1MGndaLohQEI9yQKk,3056
35
+ context_engineering/cli/registry.py,sha256=DJyeVcCvpxURW9eWpPKCPBoLxI-S4f3P6nkoWfzrT5U,928
36
+ context_engineering/cli/render.py,sha256=E1fqozVlA5DH8JYuAX5civchezLopjwkMVRDIIuuYys,3122
37
+ context_engineering/cli/subcommands.py,sha256=iIbu7VNnC7DIA3-4_jib-w0vVRAc5paB2ecMsXzvltE,18370
38
+ context_engineering/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ context_engineering/domain/commit.py,sha256=trd7vLJw06Cft_TvUItpKIcRSuVnGiwi1dDd-gD1Krw,514
40
+ context_engineering/domain/evidence.py,sha256=0xTgJJgm8nYZVR6N-l5Dg7xJB49OPH5A1peha-3PtF4,1634
41
+ context_engineering/domain/finding.py,sha256=w80d29bWZkJIfTnfRB_TEsWkeCX3NYSEsPb6Sx3zd-M,905
42
+ context_engineering/domain/result.py,sha256=Gr2Tw2J08Nijr7G1WRhj-NSJc675CV8gEqeHZFO2Pg4,1630
43
+ context_engineering/infra/__init__.py,sha256=CCkGe59MnxiVwY3kdfmRGWiN0UKYEMKJGRi5zmVLsZ0,324
44
+ context_engineering/infra/filesystem.py,sha256=4FXrGLBLmYGSVFdSJQrgrzc9Q8Gat7tglGvLjtZ5PGg,713
45
+ context_engineering/infra/git.py,sha256=xpDgjxflk_dGTiOpoU6IOiMIRbeRqZY5PkQvQ4CWl3M,4920
46
+ context_engineering/infra/git_evidence.py,sha256=aXNY9DuHUtDPVeMA7Nqc5SNYQGWdQ-B5gZ2CTYO0054,11679
47
+ context_engineering/infra/git_tree.py,sha256=-PZQbYsyXIYpJNBpP1Zo-Lt71Fbxl7LJfnppG3cmVwc,5390
48
+ context_engineering/infra/markdown.py,sha256=tHSt66r4PTYYRTUIfwIjSEDCeGFtcNBrn-YtAhgrioY,1923
49
+ context_engineering/infra/yaml_frontmatter.py,sha256=yVZamFli5iCUsvdzV2a8VAq_ETqnlciCxcX_iOEQnMY,2290
50
+ provenance.json,sha256=3elXiJzp__2KjnqNhOFW_9bkvApaF6HRlCI3lQCyYyw,599
51
+ context_engineering_cli-2.6.0.dist-info/METADATA,sha256=EO4WBUvvPudA7_HuqjZU-9rMWwl1MqOBzPjzvByl0do,1405
52
+ context_engineering_cli-2.6.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
53
+ context_engineering_cli-2.6.0.dist-info/entry_points.txt,sha256=PRSEj7vD7_aYqcfeslJIJ0VsWK2bMPh31QifshEsRis,69
54
+ context_engineering_cli-2.6.0.dist-info/licenses/LICENSE,sha256=a_2IOUCuE6IJu-MvjvKkL8hQnGtMybcXi2SAnR65YIY,1066
55
+ context_engineering_cli-2.6.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ context-engineering = context_engineering.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 safurrier
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.
provenance.json ADDED
@@ -0,0 +1 @@
1
+ {"schema": 1, "decision": "This package contains the independently authored portable Context Engineering CLI.", "entries": [{"path_prefix": "src/context_engineering/", "origin": "same-author portable implementation", "license": "MIT"}, {"path": "LICENSE", "origin": "standard MIT text", "license": "MIT"}, {"path": ".gitignore", "origin": "shared repository build exclusions", "license": "MIT"}, {"path": "pyproject.toml", "origin": "same-author package build and project metadata", "license": "MIT"}, {"path": "provenance.json", "origin": "package-scoped provenance inventory", "license": "MIT"}]}