boost-skill-cli 1.0.25__tar.gz → 1.0.27__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.25 → boost_skill_cli-1.0.27}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/discovery.py +13 -6
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/output.py +47 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/design-roadmap.html +2 -2
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_discovery.py +11 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_output.py +73 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/.gitignore +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/LICENSE +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/Makefile +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/README.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/SOURCES.txt +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/index.html +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/docs/roadmap.html +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/setup.cfg +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/style/README.md +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/style/boost.css +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/style/boost.js +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/style/demo.html +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/tests/unit/test_version.py +0 -0
|
@@ -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.27'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 27)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -212,13 +212,19 @@ def cmd_search(argv):
|
|
|
212
212
|
# Cap the name column so one long name can't pad every row, and clip each
|
|
213
213
|
# description to the remaining terminal width so results stay one line each.
|
|
214
214
|
name_w = min(max(len(e["name"]) for e, _ in shown), 32)
|
|
215
|
+
top = max((s for _e, s in shown), default=0) or 1
|
|
215
216
|
cols = out.term_width()
|
|
216
|
-
for e,
|
|
217
|
+
for e, sc in shown:
|
|
218
|
+
# A relevance meter makes the ranking visible; tint it by magnitude.
|
|
219
|
+
frac = sc / top
|
|
220
|
+
hue = "cyan" if frac >= 0.66 else "violet" if frac >= 0.33 else "pink"
|
|
221
|
+
bar = out.aurora(out.meter(frac), hue)
|
|
217
222
|
tag = " " + out.c("★ curated", out.YELLOW) if e.get("curated") else ""
|
|
218
223
|
tag_w = len(" ★ curated") if e.get("curated") else 0
|
|
219
|
-
desc_w = max(cols - 2 - name_w - 2 - tag_w, 8)
|
|
224
|
+
desc_w = max(cols - 2 - 5 - name_w - 2 - tag_w, 8) # 5 = meter + space
|
|
220
225
|
name_cell = out.c(out.truncate(e["name"], name_w).ljust(name_w), out.CYAN)
|
|
221
|
-
out.info(
|
|
226
|
+
out.info(bar + " " + name_cell + " "
|
|
227
|
+
+ out.truncate(e["description"] or "", desc_w) + tag)
|
|
222
228
|
out.info(out.c("%d match%s · ranked by %s"
|
|
223
229
|
% (len(scored), "" if len(scored) == 1 else "es", ranker),
|
|
224
230
|
out.DIM))
|
|
@@ -710,7 +716,8 @@ def cmd_count(argv):
|
|
|
710
716
|
print(json.dumps({"installed": installed_n, "available": available_n,
|
|
711
717
|
"taps": taps_n, "discovery": discovery}))
|
|
712
718
|
return 0
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
719
|
+
summary = ("installed %d · available %d (across %d tap%s) · discovery index %s"
|
|
720
|
+
% (installed_n, available_n, taps_n, "" if taps_n == 1 else "s",
|
|
721
|
+
discovery if discovery is not None else "not built"))
|
|
722
|
+
print(out.panel(summary, title="inventory"))
|
|
716
723
|
return 0
|
|
@@ -10,6 +10,7 @@ Conventions used across all commands:
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
+
import re
|
|
13
14
|
import shutil
|
|
14
15
|
import sys
|
|
15
16
|
|
|
@@ -183,6 +184,52 @@ def badge(label: str, hue: str = "cyan") -> str:
|
|
|
183
184
|
return aurora("[" + label + "]", hue)
|
|
184
185
|
|
|
185
186
|
|
|
187
|
+
_ANSI_RE = re.compile(r"\033\[[0-9;]*m")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def visible_len(s: str) -> int:
|
|
191
|
+
"""Length of a string ignoring ANSI color escapes — its column width."""
|
|
192
|
+
return len(_ANSI_RE.sub("", s))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def panel(lines, title: str | None = None, hue: str = "cyan") -> str:
|
|
196
|
+
"""A rounded box around one or more lines, with an Aurora-tinted border and
|
|
197
|
+
an optional title set into the top rule — the terminal echo of the web
|
|
198
|
+
design system's .glass / .window surfaces. Plain box under NO_COLOR.
|
|
199
|
+
"""
|
|
200
|
+
if isinstance(lines, str):
|
|
201
|
+
lines = [lines]
|
|
202
|
+
widths = [visible_len(x) for x in lines]
|
|
203
|
+
tw = visible_len(title) if title else 0
|
|
204
|
+
inner = max(widths + [tw + 2]) # a titled rule needs a space each side
|
|
205
|
+
|
|
206
|
+
def b(s: str) -> str:
|
|
207
|
+
return aurora(s, hue)
|
|
208
|
+
|
|
209
|
+
rows = []
|
|
210
|
+
if title:
|
|
211
|
+
rows.append(b("╭─ ") + c(title, BOLD) + b(" " + "─" * (inner - tw - 1) + "╮"))
|
|
212
|
+
else:
|
|
213
|
+
rows.append(b("╭" + "─" * (inner + 2) + "╮"))
|
|
214
|
+
for x, xw in zip(lines, widths):
|
|
215
|
+
rows.append(b("│ ") + x + " " * (inner - xw) + b(" │"))
|
|
216
|
+
rows.append(b("╰" + "─" * (inner + 2) + "╯"))
|
|
217
|
+
return "\n".join(rows)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def meter(fraction: float, width: int = 4) -> str:
|
|
221
|
+
"""A tiny proportional bar for a 0..1 fraction — filled ▰ vs empty ▱.
|
|
222
|
+
|
|
223
|
+
Uncolored on purpose so callers can Aurora-tint it by magnitude.
|
|
224
|
+
"""
|
|
225
|
+
if fraction < 0:
|
|
226
|
+
fraction = 0.0
|
|
227
|
+
elif fraction > 1:
|
|
228
|
+
fraction = 1.0
|
|
229
|
+
filled = round(fraction * width)
|
|
230
|
+
return "▰" * filled + "▱" * (width - filled)
|
|
231
|
+
|
|
232
|
+
|
|
186
233
|
def kv(key: str, value: str, width: int = 14) -> None:
|
|
187
234
|
print(" " + c(key.ljust(width), DIM) + str(value))
|
|
188
235
|
|
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
</article>
|
|
287
287
|
|
|
288
288
|
<article class="ritem" data-track="layout" data-impact="med">
|
|
289
|
-
<div class="ritem-top"><span class="rid">BOOST-D06</span><span class="rstatus
|
|
289
|
+
<div class="ritem-top"><span class="rid">BOOST-D06</span><span class="rstatus done">Shipped</span></div>
|
|
290
290
|
<h4>Glass-panel box primitives</h4>
|
|
291
291
|
<p>The web system frames everything in rounded glass; the CLI frames nothing. Add rounded box-drawing primitives (<code>╭─╮ │ ╰─╯</code>) with dim <code>--line</code> borders and an optional title, mirroring the web <code>.glass</code>/<code>.window</code> surfaces. Reusable chrome for <code>doctor</code>, <code>info</code>, <code>snapshot</code> and success summaries.</p>
|
|
292
292
|
<div class="rmeta"><span class="m-cat">layout</span><span>Complexity M</span><span class="m-imp med">Impact Med</span><span class="m-wow">★★★★☆</span></div>
|
|
@@ -294,7 +294,7 @@
|
|
|
294
294
|
</article>
|
|
295
295
|
|
|
296
296
|
<article class="ritem" data-track="layout" data-impact="med">
|
|
297
|
-
<div class="ritem-top"><span class="rid">BOOST-D07</span><span class="rstatus
|
|
297
|
+
<div class="ritem-top"><span class="rid">BOOST-D07</span><span class="rstatus done">Shipped</span></div>
|
|
298
298
|
<h4>Relevance visualization in search</h4>
|
|
299
299
|
<p>Results are "ranked by heuristic relevance" but the ranking is invisible — every row looks equal. Render a tiny gradient relevance bar or score glyph per hit and visually separate <b>curated</b> from GitHub-wide matches, so the eye lands on the best result first.</p>
|
|
300
300
|
<div class="rmeta"><span class="m-cat">layout</span><span>Complexity M</span><span class="m-imp med">Impact Med</span><span class="m-wow">★★★★☆</span></div>
|
|
@@ -69,6 +69,14 @@ class TestSearch:
|
|
|
69
69
|
assert r.out.index("commit-messages") < r.out.index("jira-integration")
|
|
70
70
|
assert "2 matches · ranked by heuristic relevance" in r.out
|
|
71
71
|
|
|
72
|
+
def test_results_show_relevance_meter(self, boost, tapped):
|
|
73
|
+
# D07: the ranking is visible as a per-result meter; the top exact
|
|
74
|
+
# match earns a full bar.
|
|
75
|
+
r = boost("search", "commit", "messages")
|
|
76
|
+
assert "▰" in r.out
|
|
77
|
+
top = next(l for l in r.out.splitlines() if "commit-messages" in l)
|
|
78
|
+
assert "▰▰▰▰" in top
|
|
79
|
+
|
|
72
80
|
def test_limit_caps_rows_but_footer_counts_all(self, boost, tapped):
|
|
73
81
|
r = boost("search", "workflow", "--limit", "1")
|
|
74
82
|
assert "tdd-workflow" in r.out
|
|
@@ -636,6 +644,9 @@ class TestCount:
|
|
|
636
644
|
r = boost("count")
|
|
637
645
|
assert ("installed 1 · available 5 (across 1 tap) · "
|
|
638
646
|
"discovery index not built") in r.out
|
|
647
|
+
# D06: framed inventory card
|
|
648
|
+
assert "╭─ inventory" in r.out
|
|
649
|
+
assert "╰" in r.out
|
|
639
650
|
|
|
640
651
|
def test_with_discovery_index_and_json(self, boost, installed):
|
|
641
652
|
_write_index(_ITEMS)
|
|
@@ -296,6 +296,79 @@ class TestBadge:
|
|
|
296
296
|
"\033[38;2;74;222;128m[installed]\033[0m")
|
|
297
297
|
|
|
298
298
|
|
|
299
|
+
class TestVisibleLen:
|
|
300
|
+
def test_plain_string(self):
|
|
301
|
+
assert output.visible_len("hello") == 5
|
|
302
|
+
|
|
303
|
+
def test_ignores_ansi_codes(self):
|
|
304
|
+
assert output.visible_len("\033[31mhi\033[0m") == 2
|
|
305
|
+
|
|
306
|
+
def test_truecolor_codes_stripped(self):
|
|
307
|
+
assert output.visible_len("\033[38;2;34;211;238m●\033[0m") == 1
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class TestPanel:
|
|
311
|
+
def test_single_line_plain(self, monkeypatch):
|
|
312
|
+
monkeypatch.setenv("NO_COLOR", "1")
|
|
313
|
+
assert output.panel("hi") == "╭────╮\n│ hi │\n╰────╯"
|
|
314
|
+
|
|
315
|
+
def test_pads_lines_to_widest(self, monkeypatch):
|
|
316
|
+
monkeypatch.setenv("NO_COLOR", "1")
|
|
317
|
+
assert output.panel(["a", "bbb"]) == (
|
|
318
|
+
"╭─────╮\n│ a │\n│ bbb │\n╰─────╯")
|
|
319
|
+
|
|
320
|
+
def test_title_in_top_rule(self, monkeypatch):
|
|
321
|
+
monkeypatch.setenv("NO_COLOR", "1")
|
|
322
|
+
# inner = max(len("hello")=5, len("x")+2=3) = 5
|
|
323
|
+
assert output.panel("hello", title="x") == (
|
|
324
|
+
"╭─ x ───╮\n│ hello │\n╰───────╯")
|
|
325
|
+
|
|
326
|
+
def test_wide_title_sets_inner_width(self, monkeypatch):
|
|
327
|
+
monkeypatch.setenv("NO_COLOR", "1")
|
|
328
|
+
# title longer than content: inner = len("widetitle")+2 = 11
|
|
329
|
+
p = output.panel("hi", title="widetitle")
|
|
330
|
+
first, mid, last = p.split("\n")
|
|
331
|
+
assert output.visible_len(first) == output.visible_len(last)
|
|
332
|
+
assert output.visible_len(mid) == output.visible_len(last)
|
|
333
|
+
|
|
334
|
+
def test_border_is_aurora_tinted_when_truecolor(self, monkeypatch):
|
|
335
|
+
monkeypatch.setenv("COLORTERM", "truecolor")
|
|
336
|
+
monkeypatch.setenv("CLICOLOR_FORCE", "1")
|
|
337
|
+
# top-left corner painted cyan #22d3ee
|
|
338
|
+
assert output.panel("x").startswith("\033[38;2;34;211;238m╭")
|
|
339
|
+
|
|
340
|
+
def test_title_is_bold_when_forced(self, monkeypatch):
|
|
341
|
+
monkeypatch.setenv("COLORTERM", "truecolor")
|
|
342
|
+
monkeypatch.setenv("CLICOLOR_FORCE", "1")
|
|
343
|
+
assert "\033[1minventory\033[0m" in output.panel("x", title="inventory")
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class TestMeter:
|
|
347
|
+
def test_full(self):
|
|
348
|
+
assert output.meter(1.0, 4) == "▰▰▰▰"
|
|
349
|
+
|
|
350
|
+
def test_empty(self):
|
|
351
|
+
assert output.meter(0.0, 4) == "▱▱▱▱"
|
|
352
|
+
|
|
353
|
+
def test_half(self):
|
|
354
|
+
assert output.meter(0.5, 4) == "▰▰▱▱"
|
|
355
|
+
|
|
356
|
+
def test_default_width_is_four(self):
|
|
357
|
+
assert output.meter(1.0) == "▰▰▰▰"
|
|
358
|
+
|
|
359
|
+
def test_clamps_above_one(self):
|
|
360
|
+
# 1.5 lands in (1, 2] — must still clamp, not overflow to 6 cells
|
|
361
|
+
assert output.meter(1.5, 4) == "▰▰▰▰"
|
|
362
|
+
assert output.meter(2.5, 4) == "▰▰▰▰"
|
|
363
|
+
|
|
364
|
+
def test_clamps_below_zero(self):
|
|
365
|
+
assert output.meter(-3.0, 4) == "▱▱▱▱"
|
|
366
|
+
|
|
367
|
+
def test_rounds_to_nearest_cell(self):
|
|
368
|
+
# 0.6 * 5 = 3.0 -> exactly three filled
|
|
369
|
+
assert output.meter(0.6, 5) == "▰▰▰▱▱"
|
|
370
|
+
|
|
371
|
+
|
|
299
372
|
class TestHelpers:
|
|
300
373
|
@pytest.fixture(autouse=True)
|
|
301
374
|
def plain(self, monkeypatch):
|
|
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.25 → boost_skill_cli-1.0.27}/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
|
{boost_skill_cli-1.0.25 → boost_skill_cli-1.0.27}/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
|