agent-wiki-cli 0.3.28__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 (47) hide show
  1. agent_wiki_cli-0.3.28.dist-info/METADATA +425 -0
  2. agent_wiki_cli-0.3.28.dist-info/RECORD +47 -0
  3. agent_wiki_cli-0.3.28.dist-info/WHEEL +5 -0
  4. agent_wiki_cli-0.3.28.dist-info/entry_points.txt +2 -0
  5. agent_wiki_cli-0.3.28.dist-info/licenses/LICENSE +21 -0
  6. agent_wiki_cli-0.3.28.dist-info/top_level.txt +1 -0
  7. llm_wiki_cli/__init__.py +7 -0
  8. llm_wiki_cli/cli.py +231 -0
  9. llm_wiki_cli/commands/__init__.py +1 -0
  10. llm_wiki_cli/commands/bootstrap_cmd.py +1072 -0
  11. llm_wiki_cli/commands/bump_cmd.py +55 -0
  12. llm_wiki_cli/commands/context_cmd.py +427 -0
  13. llm_wiki_cli/commands/extract_cmd.py +745 -0
  14. llm_wiki_cli/commands/generate_prompt_cmd.py +89 -0
  15. llm_wiki_cli/commands/hook_cmd.py +161 -0
  16. llm_wiki_cli/commands/init_cmd.py +92 -0
  17. llm_wiki_cli/commands/lint_cmd.py +294 -0
  18. llm_wiki_cli/commands/migrate_cmd.py +892 -0
  19. llm_wiki_cli/commands/release_cmd.py +163 -0
  20. llm_wiki_cli/commands/status_cmd.py +70 -0
  21. llm_wiki_cli/commands/sync_cmd.py +521 -0
  22. llm_wiki_cli/commands/trigger_cmd.py +205 -0
  23. llm_wiki_cli/commands/uninstall_cmd.py +221 -0
  24. llm_wiki_cli/commands/upgrade_cmd.py +196 -0
  25. llm_wiki_cli/config.py +318 -0
  26. llm_wiki_cli/extractors/__init__.py +46 -0
  27. llm_wiki_cli/extractors/common.py +90 -0
  28. llm_wiki_cli/extractors/go_extractor.py +143 -0
  29. llm_wiki_cli/extractors/go_scripts/go.mod +3 -0
  30. llm_wiki_cli/extractors/go_scripts/main.go +668 -0
  31. llm_wiki_cli/extractors/python_extractor.py +346 -0
  32. llm_wiki_cli/extractors/rust_extractor.py +143 -0
  33. llm_wiki_cli/extractors/rust_scripts/Cargo.lock +110 -0
  34. llm_wiki_cli/extractors/rust_scripts/Cargo.toml +11 -0
  35. llm_wiki_cli/extractors/rust_scripts/src/main.rs +803 -0
  36. llm_wiki_cli/extractors/ts_extractor.py +206 -0
  37. llm_wiki_cli/extractors/ts_scripts/extract.js +485 -0
  38. llm_wiki_cli/extractors/ts_scripts/package.json +10 -0
  39. llm_wiki_cli/services/__init__.py +0 -0
  40. llm_wiki_cli/services/circuit_breaker.py +79 -0
  41. llm_wiki_cli/services/io.py +47 -0
  42. llm_wiki_cli/services/lockfile.py +60 -0
  43. llm_wiki_cli/services/packages.py +173 -0
  44. llm_wiki_cli/services/paths.py +31 -0
  45. llm_wiki_cli/services/schema.py +214 -0
  46. llm_wiki_cli/services/secure_file.py +22 -0
  47. llm_wiki_cli/services/versioning.py +193 -0
@@ -0,0 +1,193 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ try: # Python 3.11+
7
+ import tomllib
8
+ except ModuleNotFoundError: # pragma: no cover - exercised on Python 3.9/3.10
9
+ try:
10
+ import tomli as tomllib
11
+ except ModuleNotFoundError: # pragma: no cover - dependency missing in ad-hoc envs
12
+ tomllib = None
13
+
14
+ # Supported version file patterns in priority order
15
+ VERSION_PATTERNS = [
16
+ ("pyproject.toml", re.compile(r"")),
17
+ ("setup.cfg", re.compile(r'^(version\s*=\s*)(\d+\.\d+\.\d+)', re.MULTILINE)),
18
+ ("package.json", re.compile(r'("version"\s*:\s*")(\d+\.\d+\.\d+)(")', re.MULTILINE)),
19
+ ("VERSION", re.compile(r'^(\d+\.\d+\.\d+)$', re.MULTILINE)),
20
+ ]
21
+
22
+ VERSION_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)$')
23
+ _TABLE_RE = re.compile(r"(?m)^\s*\[([^\]]+)\]\s*(?:#.*)?$")
24
+
25
+
26
+ def find_version_file(root: str = ".") -> Path | None:
27
+ """Auto-detect the version file in a project root."""
28
+ root_path = Path(root)
29
+ for filename, _ in VERSION_PATTERNS:
30
+ candidate = root_path / filename
31
+ if candidate.exists():
32
+ return candidate
33
+ return None
34
+
35
+
36
+ def read_version(path: Path) -> str | None:
37
+ """Parse X.Y.Z version from a detected file."""
38
+ content = path.read_text(encoding="utf-8")
39
+ if path.name == "pyproject.toml":
40
+ return _read_pyproject_version(content)
41
+ for filename, pattern in VERSION_PATTERNS:
42
+ if path.name == filename:
43
+ match = pattern.search(content)
44
+ if match:
45
+ # VERSION file has no prefix/suffix groups
46
+ groups = match.groups()
47
+ for g in groups:
48
+ if VERSION_RE.match(g):
49
+ return g
50
+ break
51
+ return None
52
+
53
+
54
+ def write_version(path: Path, new_version: str) -> None:
55
+ """Update the version string in-place, preserving file format."""
56
+ content = path.read_text(encoding="utf-8")
57
+ if path.name == "pyproject.toml":
58
+ updated = _write_pyproject_version(content, new_version, path)
59
+ path.write_bytes(updated.encode("utf-8"))
60
+ return
61
+
62
+ original = content
63
+ for filename, pattern in VERSION_PATTERNS:
64
+ if path.name == filename:
65
+ if filename == "VERSION":
66
+ content = pattern.sub(new_version, content)
67
+ else:
68
+ def _replacer(m):
69
+ groups = list(m.groups())
70
+ for i, g in enumerate(groups):
71
+ if VERSION_RE.match(g):
72
+ groups[i] = new_version
73
+ break
74
+ return "".join(groups)
75
+ content = pattern.sub(_replacer, content, count=1)
76
+ break
77
+ if content == original:
78
+ raise ValueError(f"Version pattern not found in {path}")
79
+ path.write_bytes(content.encode("utf-8"))
80
+
81
+
82
+ def _read_pyproject_version(text: str) -> str | None:
83
+ if tomllib is not None:
84
+ try:
85
+ data = tomllib.loads(text)
86
+ except Exception:
87
+ data = {}
88
+ project = data.get("project", {}) if isinstance(data, dict) else {}
89
+ if isinstance(project, dict):
90
+ if "version" in project.get("dynamic", []):
91
+ return None
92
+ version = project.get("version")
93
+ if isinstance(version, str) and VERSION_RE.match(version):
94
+ return version
95
+ poetry = data.get("tool", {}).get("poetry", {}) if isinstance(data, dict) else {}
96
+ if isinstance(poetry, dict):
97
+ version = poetry.get("version")
98
+ if isinstance(version, str) and VERSION_RE.match(version):
99
+ return version
100
+
101
+ project = _table_body(text, "project")
102
+ if project is not None:
103
+ if _project_version_is_dynamic(project):
104
+ return None
105
+ version = _static_version_from_body(project)
106
+ if version:
107
+ return version
108
+
109
+ poetry = _table_body(text, "tool.poetry")
110
+ if poetry is not None:
111
+ return _static_version_from_body(poetry)
112
+ return None
113
+
114
+
115
+ def _write_pyproject_version(text: str, new_version: str, path: Path) -> str:
116
+ project_bounds = _table_bounds(text, "project")
117
+ if project_bounds is not None:
118
+ start, end = project_bounds
119
+ body = text[start:end]
120
+ if _project_version_is_dynamic(body):
121
+ raise ValueError(f"{path}: [project].version is dynamic; cannot bump a static version")
122
+ updated_body, changed = _replace_static_version_line(body, new_version)
123
+ if changed:
124
+ return text[:start] + updated_body + text[end:]
125
+
126
+ poetry_bounds = _table_bounds(text, "tool.poetry")
127
+ if poetry_bounds is not None:
128
+ start, end = poetry_bounds
129
+ body = text[start:end]
130
+ updated_body, changed = _replace_static_version_line(body, new_version)
131
+ if changed:
132
+ return text[:start] + updated_body + text[end:]
133
+
134
+ raise ValueError(f"Version pattern not found in {path}")
135
+
136
+
137
+ def _table_bounds(text: str, table_name: str) -> tuple[int, int] | None:
138
+ for match in _TABLE_RE.finditer(text):
139
+ if match.group(1).strip() != table_name:
140
+ continue
141
+ start = match.end()
142
+ next_match = _TABLE_RE.search(text, start)
143
+ end = next_match.start() if next_match else len(text)
144
+ return start, end
145
+ return None
146
+
147
+
148
+ def _table_body(text: str, table_name: str) -> str | None:
149
+ bounds = _table_bounds(text, table_name)
150
+ if bounds is None:
151
+ return None
152
+ start, end = bounds
153
+ return text[start:end]
154
+
155
+
156
+ def _static_version_from_body(body: str) -> str | None:
157
+ match = re.search(r'(?m)^\s*version\s*=\s*"([^"]+)"', body)
158
+ if match and VERSION_RE.match(match.group(1)):
159
+ return match.group(1)
160
+ return None
161
+
162
+
163
+ def _replace_static_version_line(body: str, new_version: str) -> tuple[str, bool]:
164
+ pattern = re.compile(r'(?m)^(\s*version\s*=\s*")([^"]+)(".*)$')
165
+
166
+ def repl(match: re.Match[str]) -> str:
167
+ return f"{match.group(1)}{new_version}{match.group(3)}"
168
+
169
+ updated, count = pattern.subn(repl, body, count=1)
170
+ return updated, count > 0
171
+
172
+
173
+ def _project_version_is_dynamic(body: str) -> bool:
174
+ match = re.search(r'(?ms)^\s*dynamic\s*=\s*\[(.*?)\]', body)
175
+ return bool(match and re.search(r'["\']version["\']', match.group(1)))
176
+
177
+
178
+ def bump_patch(version: str) -> str:
179
+ """0.1.5 -> 0.1.6"""
180
+ m = VERSION_RE.match(version)
181
+ if not m:
182
+ raise ValueError(f"Invalid version format: {version}")
183
+ major, minor, patch = int(m.group(1)), int(m.group(2)), int(m.group(3))
184
+ return f"{major}.{minor}.{patch + 1}"
185
+
186
+
187
+ def bump_minor(version: str) -> str:
188
+ """0.1.6 -> 0.2.0"""
189
+ m = VERSION_RE.match(version)
190
+ if not m:
191
+ raise ValueError(f"Invalid version format: {version}")
192
+ major, minor, _ = int(m.group(1)), int(m.group(2)), int(m.group(3))
193
+ return f"{major}.{minor + 1}.0"