boost-skill-cli 1.0.58__tar.gz → 1.0.60__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.
- boost_skill_cli-1.0.60/.gitattributes +4 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/CONTRIBUTING.md +14 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/catalog.py +23 -1
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/scripts/build_registries.py +54 -7
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_catalog.py +26 -0
- boost_skill_cli-1.0.60/tests/unit/test_registries_fresh.py +49 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/.gitignore +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/LICENSE +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/Makefile +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/README.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/index.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/docs/roadmap.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/index.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/setup.cfg +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/style/README.md +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/style/boost.css +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/style/boost.js +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/style/demo.html +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/unit/test_version.py +0 -0
|
@@ -33,6 +33,20 @@ agent configs.
|
|
|
33
33
|
- Anything under `boost_cli/core/` is mutation-tested; expect to add unit
|
|
34
34
|
tests that actually kill your mutants.
|
|
35
35
|
|
|
36
|
+
## Generated files — never hand-edit
|
|
37
|
+
|
|
38
|
+
Some checked-in files are build outputs. Edit the source, regenerate, and commit
|
|
39
|
+
the result **as the final step before opening the PR** so the artifact never
|
|
40
|
+
drifts from its source (CI fails the build otherwise):
|
|
41
|
+
|
|
42
|
+
| Generated file | Source of truth | Regenerate with |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `boost_cli/data/registries.json` | `SKILLS`/`RULES`/`WORKFLOWS` tuples in `scripts/build_registries.py` | `python3 scripts/build_registries.py` |
|
|
45
|
+
|
|
46
|
+
CI runs `python3 scripts/build_registries.py --check` and fails on drift; the
|
|
47
|
+
same guard lives in `tests/unit/test_registries_fresh.py`. Regenerating last also
|
|
48
|
+
keeps line-adjacent JSON conflicts between parallel branches rare.
|
|
49
|
+
|
|
36
50
|
## Pull requests
|
|
37
51
|
|
|
38
52
|
Branch from `main`, keep PRs focused, and write the PR description in the
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
21
|
+
__version__ = version = '1.0.60'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 60)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -210,6 +210,28 @@ def resolve_one(name: str) -> dict:
|
|
|
210
210
|
return matches[0]
|
|
211
211
|
|
|
212
212
|
|
|
213
|
+
def _meta_text(meta) -> str:
|
|
214
|
+
"""Lowercased, space-joined flatten of a frontmatter dict for substring
|
|
215
|
+
search. Cheaper than ``json.dumps(meta).lower()`` — which built and threw
|
|
216
|
+
away a JSON string on every entry of every query just to substring-match —
|
|
217
|
+
while matching the same words (tags, keys, scalar values)."""
|
|
218
|
+
parts: List[str] = []
|
|
219
|
+
|
|
220
|
+
def walk(v) -> None:
|
|
221
|
+
if isinstance(v, dict):
|
|
222
|
+
for k, val in v.items():
|
|
223
|
+
parts.append(str(k))
|
|
224
|
+
walk(val)
|
|
225
|
+
elif isinstance(v, (list, tuple)):
|
|
226
|
+
for val in v:
|
|
227
|
+
walk(val)
|
|
228
|
+
elif v is not None:
|
|
229
|
+
parts.append(str(v))
|
|
230
|
+
|
|
231
|
+
walk(meta or {})
|
|
232
|
+
return " ".join(parts).lower()
|
|
233
|
+
|
|
234
|
+
|
|
213
235
|
def search(query: str, entries: Optional[List[dict]] = None):
|
|
214
236
|
"""Rank entries against a query -> [(entry, score)] best-first."""
|
|
215
237
|
entries = all_entries() if entries is None else entries
|
|
@@ -219,7 +241,7 @@ def search(query: str, entries: Optional[List[dict]] = None):
|
|
|
219
241
|
for e in entries:
|
|
220
242
|
name = e["name"].lower()
|
|
221
243
|
desc = (e["description"] or "").lower()
|
|
222
|
-
blob = " ".join([name, desc,
|
|
244
|
+
blob = " ".join([name, desc, _meta_text(e.get("meta", {}))])
|
|
223
245
|
score = 0
|
|
224
246
|
if q == name:
|
|
225
247
|
score += 100
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
.gitattributes
|
|
1
2
|
.gitignore
|
|
2
3
|
CLAUDE.md
|
|
3
4
|
CONTRIBUTING.md
|
|
@@ -106,6 +107,7 @@ tests/unit/test_output.py
|
|
|
106
107
|
tests/unit/test_paths.py
|
|
107
108
|
tests/unit/test_policy.py
|
|
108
109
|
tests/unit/test_rag.py
|
|
110
|
+
tests/unit/test_registries_fresh.py
|
|
109
111
|
tests/unit/test_registry.py
|
|
110
112
|
tests/unit/test_spin.py
|
|
111
113
|
tests/unit/test_store.py
|
|
@@ -6,13 +6,18 @@ entry is deduped by owner/repo, classified by type + category, and tagged with
|
|
|
6
6
|
`list_only` when the repo is an awesome-list that mostly links out (so its
|
|
7
7
|
scannable item count is far below its advertised total).
|
|
8
8
|
|
|
9
|
-
Run:
|
|
9
|
+
Run: python3 scripts/build_registries.py # regenerate the JSON
|
|
10
|
+
Verify: python3 scripts/build_registries.py --check # fail if it has drifted
|
|
10
11
|
"""
|
|
11
12
|
from __future__ import annotations
|
|
12
13
|
|
|
14
|
+
import argparse
|
|
13
15
|
import json
|
|
16
|
+
import sys
|
|
14
17
|
from pathlib import Path
|
|
15
18
|
|
|
19
|
+
DEST = Path(__file__).resolve().parent.parent / "boost_cli" / "data" / "registries.json"
|
|
20
|
+
|
|
16
21
|
# Repos that are index/awesome READMEs — they *point at* many items but ship
|
|
17
22
|
# few or no scannable item files themselves. Kept for discovery, flagged so
|
|
18
23
|
# count math stays honest.
|
|
@@ -163,7 +168,12 @@ def rows(pairs, typ):
|
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
|
|
166
|
-
def
|
|
171
|
+
def build_payload() -> dict:
|
|
172
|
+
"""Assemble the registries payload from the SKILLS/RULES/WORKFLOWS tuples.
|
|
173
|
+
|
|
174
|
+
Pure function of the source tuples — no I/O — so both the writer and the
|
|
175
|
+
``--check`` verifier render byte-for-byte identical output.
|
|
176
|
+
"""
|
|
167
177
|
by_name: dict = {}
|
|
168
178
|
for entry in list(rows(SKILLS, "skill")) + list(rows(RULES, "rule")) + \
|
|
169
179
|
list(rows(WORKFLOWS, "workflow")):
|
|
@@ -181,7 +191,7 @@ def main() -> int:
|
|
|
181
191
|
|
|
182
192
|
entries = sorted(by_name.values(), key=lambda e: (e["type"], e["name"].lower()))
|
|
183
193
|
scannable = [e for e in entries if not e["list_only"]]
|
|
184
|
-
|
|
194
|
+
return {
|
|
185
195
|
"generated_note": "Curated skill/rule/workflow registries for boost. "
|
|
186
196
|
"est_items are research estimates; verify by tapping. "
|
|
187
197
|
"list_only repos are index/awesome lists that link out.",
|
|
@@ -190,10 +200,16 @@ def main() -> int:
|
|
|
190
200
|
"est_items_scannable": sum(e["est_items"] for e in scannable),
|
|
191
201
|
"registries": entries,
|
|
192
202
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def render(payload: dict) -> str:
|
|
206
|
+
"""Serialize a payload to the exact on-disk representation."""
|
|
207
|
+
return json.dumps(payload, indent=2) + "\n"
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _summary(payload: dict) -> None:
|
|
211
|
+
entries = payload["registries"]
|
|
212
|
+
scannable = [e for e in entries if not e["list_only"]]
|
|
197
213
|
print("registries: %d (scannable %d, list-only %d)"
|
|
198
214
|
% (len(entries), len(scannable), len(entries) - len(scannable)))
|
|
199
215
|
print("est items total: %d scannable: %d"
|
|
@@ -205,6 +221,37 @@ def main() -> int:
|
|
|
205
221
|
by_type[e["type"]][1] += e["est_items"]
|
|
206
222
|
for typ, (n, est) in sorted(by_type.items()):
|
|
207
223
|
print(" %-9s %3d repos ~%d items" % (typ, n, est))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def main(argv: list[str] | None = None) -> int:
|
|
227
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
228
|
+
parser.add_argument(
|
|
229
|
+
"--check", action="store_true",
|
|
230
|
+
help="verify the committed JSON matches a fresh build; exit 1 on drift "
|
|
231
|
+
"(does not write). Used in CI to catch un-regenerated edits.",
|
|
232
|
+
)
|
|
233
|
+
args = parser.parse_args(argv)
|
|
234
|
+
|
|
235
|
+
payload = build_payload()
|
|
236
|
+
fresh = render(payload)
|
|
237
|
+
|
|
238
|
+
if args.check:
|
|
239
|
+
current = DEST.read_text() if DEST.exists() else ""
|
|
240
|
+
if current != fresh:
|
|
241
|
+
print(
|
|
242
|
+
"ERROR: %s is out of date — regenerate it with\n"
|
|
243
|
+
" python3 scripts/build_registries.py\n"
|
|
244
|
+
"and commit the result (see CONTRIBUTING.md)." % DEST,
|
|
245
|
+
file=sys.stderr,
|
|
246
|
+
)
|
|
247
|
+
return 1
|
|
248
|
+
print("%s is up to date." % DEST)
|
|
249
|
+
return 0
|
|
250
|
+
|
|
251
|
+
DEST.parent.mkdir(parents=True, exist_ok=True)
|
|
252
|
+
DEST.write_text(fresh)
|
|
253
|
+
print("wrote %s" % DEST)
|
|
254
|
+
_summary(payload)
|
|
208
255
|
return 0
|
|
209
256
|
|
|
210
257
|
|
|
@@ -443,6 +443,32 @@ class TestSearchRanking:
|
|
|
443
443
|
res = catalog.search("security", entries=[e])
|
|
444
444
|
assert [(m["name"], s) for m, s in res] == [("x", 2)]
|
|
445
445
|
|
|
446
|
+
def test_meta_key_still_matches(self):
|
|
447
|
+
# keys are part of the search text, just as json.dumps(meta) included
|
|
448
|
+
# them — a query for a frontmatter key name still scores.
|
|
449
|
+
e = _entry("x", "t", meta={"framework": "react"})
|
|
450
|
+
assert [(m["name"], s) for m, s in catalog.search("framework", entries=[e])] \
|
|
451
|
+
== [("x", 2)]
|
|
452
|
+
|
|
453
|
+
def test_meta_nested_value_matches(self):
|
|
454
|
+
e = _entry("x", "t", meta={"requires": [{"skill": "planning"}]})
|
|
455
|
+
assert [(m["name"], s) for m, s in catalog.search("planning", entries=[e])] \
|
|
456
|
+
== [("x", 2)]
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
class TestMetaText:
|
|
460
|
+
def test_flattens_keys_and_values_lowercased(self):
|
|
461
|
+
assert catalog._meta_text({"Tags": ["AI", "ML"]}) == "tags ai ml"
|
|
462
|
+
|
|
463
|
+
def test_nested_dicts_and_lists(self):
|
|
464
|
+
out = catalog._meta_text({"a": {"b": [1, "Two"]}})
|
|
465
|
+
assert out == "a b 1 two"
|
|
466
|
+
|
|
467
|
+
def test_skips_none_and_empty(self):
|
|
468
|
+
assert catalog._meta_text({}) == ""
|
|
469
|
+
assert catalog._meta_text(None) == ""
|
|
470
|
+
assert catalog._meta_text({"k": None}) == "k"
|
|
471
|
+
|
|
446
472
|
def test_description_only_match(self):
|
|
447
473
|
e = _entry("styler", "t", desc="handles jira tickets")
|
|
448
474
|
res = catalog.search("jira", entries=[e])
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Committed registries.json stays in lockstep with its generator.
|
|
2
|
+
|
|
3
|
+
``boost_cli/data/registries.json`` is a generated artifact (source of truth is
|
|
4
|
+
the SKILLS/RULES/WORKFLOWS tuples in ``scripts/build_registries.py``). If a repo
|
|
5
|
+
row is edited without regenerating, the committed JSON drifts. This test — the
|
|
6
|
+
in-suite twin of the ``build_registries.py --check`` CI step — fails on drift so
|
|
7
|
+
a stale artifact can't merge.
|
|
8
|
+
|
|
9
|
+
Skips when the repo-root files aren't reachable (e.g. the mutation sandbox,
|
|
10
|
+
which only copies ``boost_cli/``).
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import importlib.util
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
_ROOT = Path(__file__).resolve().parents[2]
|
|
20
|
+
_SCRIPT = _ROOT / "scripts" / "build_registries.py"
|
|
21
|
+
_JSON = _ROOT / "boost_cli" / "data" / "registries.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _load_builder():
|
|
25
|
+
spec = importlib.util.spec_from_file_location("build_registries", _SCRIPT)
|
|
26
|
+
assert spec and spec.loader
|
|
27
|
+
module = importlib.util.module_from_spec(spec)
|
|
28
|
+
spec.loader.exec_module(module)
|
|
29
|
+
return module
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.skipif(not (_SCRIPT.exists() and _JSON.exists()),
|
|
33
|
+
reason="repo-root files not reachable (e.g. mutation sandbox)")
|
|
34
|
+
def test_registries_json_is_regenerated():
|
|
35
|
+
builder = _load_builder()
|
|
36
|
+
fresh = builder.render(builder.build_payload())
|
|
37
|
+
committed = _JSON.read_text()
|
|
38
|
+
assert committed == fresh, (
|
|
39
|
+
"boost_cli/data/registries.json is out of date — regenerate with\n"
|
|
40
|
+
" python3 scripts/build_registries.py\n"
|
|
41
|
+
"and commit the result (see CONTRIBUTING.md)."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.skipif(not _SCRIPT.exists(),
|
|
46
|
+
reason="repo-root files not reachable (e.g. mutation sandbox)")
|
|
47
|
+
def test_check_flag_passes_on_fresh_tree():
|
|
48
|
+
builder = _load_builder()
|
|
49
|
+
assert builder.main(["--check"]) == 0
|
|
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
|
|
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
|
{boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/boost_skill_cli.egg-info/dependency_links.txt
RENAMED
|
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
|
{boost_skill_cli-1.0.58 → boost_skill_cli-1.0.60}/tests/functional/test_cli_configuration.py
RENAMED
|
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
|
|
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
|