boost-skill-cli 1.0.38__tar.gz → 1.0.40__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.38 → boost_skill_cli-1.0.40}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/discovery.py +3 -2
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/info.py +7 -3
- boost_skill_cli-1.0.40/boost_cli/spin.py +56 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/design-roadmap.html +1 -1
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/roadmap.html +141 -1
- boost_skill_cli-1.0.40/tests/unit/test_spin.py +71 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/.gitignore +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/LICENSE +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/Makefile +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/README.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/index.html +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/setup.cfg +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/style/README.md +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/style/boost.css +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/style/boost.js +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/style/demo.html +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/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.40'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 40)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -15,7 +15,7 @@ import sys
|
|
|
15
15
|
import time
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
|
-
from .. import cliparse
|
|
18
|
+
from .. import cliparse, spin
|
|
19
19
|
from ..core import agents, ai, catalog, dense, embed, gitutil, journal, lockfile, paths, rag, registry, store, util
|
|
20
20
|
from ..core import output as out
|
|
21
21
|
from ..errors import BoostError
|
|
@@ -204,7 +204,8 @@ def cmd_search(argv):
|
|
|
204
204
|
ranker = "full-content BM25" if use_rag else "heuristic relevance"
|
|
205
205
|
if args.smart:
|
|
206
206
|
if ai.available():
|
|
207
|
-
|
|
207
|
+
with spin.Spinner("ranking %d matches with Claude" % len(scored)):
|
|
208
|
+
reranked = _ai_rank(query, scored)
|
|
208
209
|
if reranked:
|
|
209
210
|
scored, ranker = reranked, "Claude Haiku relevance"
|
|
210
211
|
else:
|
|
@@ -123,9 +123,13 @@ def cmd_list(argv):
|
|
|
123
123
|
rows = []
|
|
124
124
|
for name in sorted(skills):
|
|
125
125
|
e = skills[name]
|
|
126
|
-
flags
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
# Aurora-tinted flags — now that table() aligns by visible width,
|
|
127
|
+
# colored cells stay in their column: pinned amber, quarantined pink,
|
|
128
|
+
# tags dim.
|
|
129
|
+
flags = ([out.aurora("pinned", "yellow")] if e.get("pinned") else []) + \
|
|
130
|
+
([out.aurora("quarantined", "pink")] if e.get("quarantined")
|
|
131
|
+
else []) + \
|
|
132
|
+
[out.c("#" + t, out.DIM) for t in e.get("tags") or []]
|
|
129
133
|
rows.append((name, e.get("version", "?"), e.get("tap", "?"),
|
|
130
134
|
"·".join(a.split("-")[0] for a in e.get("agents") or []),
|
|
131
135
|
" ".join(flags)))
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""A braille spinner for indeterminate waits (network calls, AI reranking…).
|
|
2
|
+
|
|
3
|
+
Deliberately silent — no thread, no output — whenever the stream isn't an
|
|
4
|
+
interactive TTY or color is off, so piped output, CI logs and captured test
|
|
5
|
+
output stay clean. Usage:
|
|
6
|
+
|
|
7
|
+
with spin.Spinner("ranking with Claude"):
|
|
8
|
+
result = slow_network_call()
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import itertools
|
|
13
|
+
import sys
|
|
14
|
+
import threading
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from .core import output as out
|
|
18
|
+
|
|
19
|
+
_FRAMES = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
20
|
+
_INTERVAL = 0.08
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Spinner:
|
|
24
|
+
def __init__(self, label: str = "", stream=None):
|
|
25
|
+
self.label = label
|
|
26
|
+
self.stream = stream if stream is not None else sys.stderr
|
|
27
|
+
self._stop = threading.Event()
|
|
28
|
+
self._thread: Optional[threading.Thread] = None
|
|
29
|
+
|
|
30
|
+
def active(self) -> bool:
|
|
31
|
+
"""Animate only on an interactive, color-capable TTY."""
|
|
32
|
+
s = self.stream
|
|
33
|
+
return (out.color_level(s) > 0
|
|
34
|
+
and hasattr(s, "isatty") and s.isatty())
|
|
35
|
+
|
|
36
|
+
def __enter__(self) -> "Spinner":
|
|
37
|
+
if self.active():
|
|
38
|
+
self._thread = threading.Thread(target=self._spin, daemon=True)
|
|
39
|
+
self._thread.start()
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def _spin(self) -> None:
|
|
43
|
+
for frame in itertools.cycle(_FRAMES):
|
|
44
|
+
if self._stop.is_set():
|
|
45
|
+
break
|
|
46
|
+
self.stream.write("\r" + out.aurora(frame, "cyan") + " " + self.label)
|
|
47
|
+
self.stream.flush()
|
|
48
|
+
self._stop.wait(_INTERVAL)
|
|
49
|
+
|
|
50
|
+
def __exit__(self, *exc) -> None:
|
|
51
|
+
self._stop.set()
|
|
52
|
+
if self._thread is not None:
|
|
53
|
+
self._thread.join(timeout=1)
|
|
54
|
+
if self.active():
|
|
55
|
+
self.stream.write("\r" + " " * (out.visible_len(self.label) + 2) + "\r")
|
|
56
|
+
self.stream.flush()
|
|
@@ -15,6 +15,7 @@ boost_cli/_version.py
|
|
|
15
15
|
boost_cli/cli.py
|
|
16
16
|
boost_cli/cliparse.py
|
|
17
17
|
boost_cli/errors.py
|
|
18
|
+
boost_cli/spin.py
|
|
18
19
|
boost_cli/commands/__init__.py
|
|
19
20
|
boost_cli/commands/bmad.py
|
|
20
21
|
boost_cli/commands/configuration.py
|
|
@@ -101,6 +102,7 @@ tests/unit/test_paths.py
|
|
|
101
102
|
tests/unit/test_policy.py
|
|
102
103
|
tests/unit/test_rag.py
|
|
103
104
|
tests/unit/test_registry.py
|
|
105
|
+
tests/unit/test_spin.py
|
|
104
106
|
tests/unit/test_store.py
|
|
105
107
|
tests/unit/test_util.py
|
|
106
108
|
tests/unit/test_version.py
|
|
@@ -349,7 +349,7 @@
|
|
|
349
349
|
<div class="rcards">
|
|
350
350
|
|
|
351
351
|
<article class="ritem" data-track="motion" data-impact="high">
|
|
352
|
-
<div class="ritem-top"><span class="rid">BOOST-D10</span><span class="rstatus
|
|
352
|
+
<div class="ritem-top"><span class="rid">BOOST-D10</span><span class="rstatus done">Shipped</span></div>
|
|
353
353
|
<h4>Braille spinner for network waits</h4>
|
|
354
354
|
<p>Network-bound commands — <code>search</code> (AI rank), <code>tap</code> clone, <code>discover</code>, <code>index</code> — currently freeze silently while they work. Add a lightweight braille-dot spinner (<code>⠋⠙⠹⠸…</code>) tinted with the Aurora accent, auto-suppressed on non-TTY and under <code>NO_COLOR</code>. The single biggest "feels fast" upgrade.</p>
|
|
355
355
|
<div class="rmeta"><span class="m-cat">motion</span><span>Complexity S</span><span class="m-imp high">Impact High</span><span class="m-wow">★★★★☆</span></div>
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
<div class="stat"><b>4</b><span>Shipped</span></div>
|
|
117
117
|
<div class="stat"><b>3</b><span>Next up</span></div>
|
|
118
118
|
<div class="stat"><b>4</b><span>Planned</span></div>
|
|
119
|
-
<div class="stat"><b>
|
|
119
|
+
<div class="stat"><b>32</b><span>Loop finds</span></div>
|
|
120
120
|
</div>
|
|
121
121
|
</section>
|
|
122
122
|
|
|
@@ -732,6 +732,146 @@
|
|
|
732
732
|
</div>
|
|
733
733
|
</section>
|
|
734
734
|
|
|
735
|
+
<!-- ============ DOCS-SITE & CONTENT QUALITY ============ -->
|
|
736
|
+
<section class="block reveal" id="docsite">
|
|
737
|
+
<div class="block-head">
|
|
738
|
+
<h2>Docs-site & content quality</h2>
|
|
739
|
+
<span class="count">// planned · free tooling for the Pages site, README & prose</span>
|
|
740
|
+
<span class="rule"></span>
|
|
741
|
+
</div>
|
|
742
|
+
<div class="rgrid">
|
|
743
|
+
|
|
744
|
+
<article class="cap rcard">
|
|
745
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Docs · Perf</span></div>
|
|
746
|
+
<h3>Lighthouse CI on the Pages site</h3>
|
|
747
|
+
<p><code>treosh/lighthouse-ci-action</code> scores <code>index.html</code>
|
|
748
|
+
and <code>roadmap.html</code> on performance, accessibility,
|
|
749
|
+
best-practices and SEO on every deploy, and fails the build against
|
|
750
|
+
budgets. Turns the marketing surface's quality into a number that can't
|
|
751
|
+
silently regress as the Aurora theme evolves.</p>
|
|
752
|
+
<div class="meta">
|
|
753
|
+
<span class="m">Complexity <b>M</b></span>
|
|
754
|
+
<span class="m hi">Impact <b>High</b></span>
|
|
755
|
+
<span class="m">Wow <b class="wow">★★★★★</b></span>
|
|
756
|
+
<span class="m">4 score budgets</span>
|
|
757
|
+
</div>
|
|
758
|
+
</article>
|
|
759
|
+
|
|
760
|
+
<article class="cap rcard">
|
|
761
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · A11y</span></div>
|
|
762
|
+
<h3>Accessibility audit — <code>pa11y-ci</code> / axe-core</h3>
|
|
763
|
+
<p>Run WCAG checks over the rendered pages: colour contrast, focus order,
|
|
764
|
+
alt text and ARIA. The Aurora palette leans on muted
|
|
765
|
+
<code>--text-2/--text-3</code> tokens against dark glass — exactly where
|
|
766
|
+
contrast ratios slip below AA. Catches the a11y regressions a purely
|
|
767
|
+
visual review misses.</p>
|
|
768
|
+
<div class="meta">
|
|
769
|
+
<span class="m">Complexity <b>M</b></span>
|
|
770
|
+
<span class="m">Impact <b>Med</b></span>
|
|
771
|
+
<span class="m">Wow <b class="wow">★★★★</b></span>
|
|
772
|
+
<span class="m">WCAG AA</span>
|
|
773
|
+
</div>
|
|
774
|
+
</article>
|
|
775
|
+
|
|
776
|
+
<article class="cap rcard">
|
|
777
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Docs</span></div>
|
|
778
|
+
<h3>HTML validation — <code>html-validate</code></h3>
|
|
779
|
+
<p>The guide and roadmap are hand-authored HTML whose tags are balanced by
|
|
780
|
+
eye today. A CI <code>html-validate</code> pass catches unclosed
|
|
781
|
+
elements, duplicate <code>id</code>s and invalid nesting before they
|
|
782
|
+
ship a subtly broken layout — the automated version of the manual
|
|
783
|
+
tag-count sanity check.</p>
|
|
784
|
+
<div class="meta">
|
|
785
|
+
<span class="m">Complexity <b>S</b></span>
|
|
786
|
+
<span class="m">Impact <b>Med</b></span>
|
|
787
|
+
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
788
|
+
<span class="m">hand-authored HTML</span>
|
|
789
|
+
</div>
|
|
790
|
+
</article>
|
|
791
|
+
|
|
792
|
+
<article class="cap rcard">
|
|
793
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Docs</span></div>
|
|
794
|
+
<h3>Broken-link & anchor checking — <code>lychee</code></h3>
|
|
795
|
+
<p>Fast, free link checker over the README and <code>docs/*.html</code>:
|
|
796
|
+
verifies external URLs (GitHub, PyPI), asset paths
|
|
797
|
+
(<code>../style/boost.css</code>) and in-page anchors
|
|
798
|
+
(<code>#next</code>, <code>#health</code>) still resolve. A dead link in
|
|
799
|
+
the landing page is the first broken promise a visitor sees.</p>
|
|
800
|
+
<div class="meta">
|
|
801
|
+
<span class="m">Complexity <b>S</b></span>
|
|
802
|
+
<span class="m">Impact <b>Med</b></span>
|
|
803
|
+
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
804
|
+
<span class="m">URLs + anchors</span>
|
|
805
|
+
</div>
|
|
806
|
+
</article>
|
|
807
|
+
|
|
808
|
+
<article class="cap rcard">
|
|
809
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Content</span></div>
|
|
810
|
+
<h3>Prose & terminology linting — <code>vale</code></h3>
|
|
811
|
+
<p><code>vale</code> enforces a consistent voice across the README and docs
|
|
812
|
+
with a small boost vocabulary — canonical spelling of <em>skill</em>,
|
|
813
|
+
<em>tap</em>, <em>registry</em>; no <code>Boost</code>/<code>boost</code>
|
|
814
|
+
drift; flagged weasel words. Keeps a docs-heavy project reading like one
|
|
815
|
+
author wrote it.</p>
|
|
816
|
+
<div class="meta">
|
|
817
|
+
<span class="m">Complexity <b>S</b></span>
|
|
818
|
+
<span class="m">Impact <b>Low</b></span>
|
|
819
|
+
<span class="m">Wow <b class="wow">★★</b></span>
|
|
820
|
+
<span class="m">house style</span>
|
|
821
|
+
</div>
|
|
822
|
+
</article>
|
|
823
|
+
|
|
824
|
+
<article class="cap rcard">
|
|
825
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Docs</span></div>
|
|
826
|
+
<h3>Markdown consistency — <code>markdownlint-cli2</code></h3>
|
|
827
|
+
<p>Lint every Markdown surface — README, <code>CLAUDE.md</code>,
|
|
828
|
+
<code>DEBUGGING.md</code>, <code>rag-architecture.md</code> — for
|
|
829
|
+
heading order, list style and fenced-code hygiene. Cheap, deterministic,
|
|
830
|
+
and it keeps the contributor-facing docs as tidy as the code the gates
|
|
831
|
+
already enforce.</p>
|
|
832
|
+
<div class="meta">
|
|
833
|
+
<span class="m">Complexity <b>S</b></span>
|
|
834
|
+
<span class="m">Impact <b>Low</b></span>
|
|
835
|
+
<span class="m">Wow <b class="wow">★★</b></span>
|
|
836
|
+
<span class="m">every .md</span>
|
|
837
|
+
</div>
|
|
838
|
+
</article>
|
|
839
|
+
|
|
840
|
+
<article class="cap rcard">
|
|
841
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Style</span></div>
|
|
842
|
+
<h3>Theme-asset linting — <code>stylelint</code> + <code>eslint</code></h3>
|
|
843
|
+
<p>The shared <code>style/boost.css</code> and <code>boost.js</code> theme
|
|
844
|
+
the guide, roadmap and demo together, so a bug there recolours or breaks
|
|
845
|
+
everything at once. <code>stylelint</code> guards the CSS tokens and
|
|
846
|
+
<code>eslint</code> the reveal/interaction JS — the one place a small
|
|
847
|
+
mistake has system-wide blast radius.</p>
|
|
848
|
+
<div class="meta">
|
|
849
|
+
<span class="m">Complexity <b>S</b></span>
|
|
850
|
+
<span class="m">Impact <b>Med</b></span>
|
|
851
|
+
<span class="m">Wow <b class="wow">★★</b></span>
|
|
852
|
+
<span class="m">shared blast radius</span>
|
|
853
|
+
</div>
|
|
854
|
+
</article>
|
|
855
|
+
|
|
856
|
+
<article class="cap rcard">
|
|
857
|
+
<div class="head"><span class="pill planned">Planned</span><span class="cat">Testing · Docs</span></div>
|
|
858
|
+
<h3>Post-deploy smoke — headless load check</h3>
|
|
859
|
+
<p>After each Pages deploy, headless-load the guide and roadmap and assert
|
|
860
|
+
the essentials: HTTP 200, every asset resolves, and the console is free
|
|
861
|
+
of errors. Distinct from the planned visual-regression pass — this is a
|
|
862
|
+
cheap always-on health gate that would have caught the current broken
|
|
863
|
+
Pages deploy automatically.</p>
|
|
864
|
+
<div class="meta">
|
|
865
|
+
<span class="m">Complexity <b>M</b></span>
|
|
866
|
+
<span class="m">Impact <b>Med</b></span>
|
|
867
|
+
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
868
|
+
<span class="m">catches red deploys</span>
|
|
869
|
+
</div>
|
|
870
|
+
</article>
|
|
871
|
+
|
|
872
|
+
</div>
|
|
873
|
+
</section>
|
|
874
|
+
|
|
735
875
|
<footer>
|
|
736
876
|
<p>Maintained by the boost quality loop · themed with
|
|
737
877
|
<a href="../style/boost.css">style/boost.css</a> ·
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Unit tests: boost_cli/spin.Spinner — the TTY-guarded braille spinner."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import io
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from boost_cli import spin
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FakeStream(io.StringIO):
|
|
12
|
+
def __init__(self, tty):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self._tty = tty
|
|
15
|
+
|
|
16
|
+
def isatty(self):
|
|
17
|
+
return self._tty
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture(autouse=True)
|
|
21
|
+
def force_color(monkeypatch):
|
|
22
|
+
# color on, so `active()` hinges purely on the TTY check
|
|
23
|
+
monkeypatch.delenv("NO_COLOR", raising=False)
|
|
24
|
+
monkeypatch.setenv("CLICOLOR_FORCE", "1")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_silent_on_non_tty():
|
|
28
|
+
s = FakeStream(tty=False)
|
|
29
|
+
with spin.Spinner("working", stream=s) as sp:
|
|
30
|
+
pass
|
|
31
|
+
assert sp.active() is False
|
|
32
|
+
assert s.getvalue() == "" # nothing written, no thread started
|
|
33
|
+
assert sp._thread is None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_no_color_is_silent(monkeypatch):
|
|
37
|
+
monkeypatch.delenv("CLICOLOR_FORCE", raising=False)
|
|
38
|
+
monkeypatch.setenv("NO_COLOR", "1")
|
|
39
|
+
s = FakeStream(tty=True) # a TTY, but color is off
|
|
40
|
+
with spin.Spinner("working", stream=s):
|
|
41
|
+
pass
|
|
42
|
+
assert s.getvalue() == ""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_active_on_color_tty():
|
|
46
|
+
assert spin.Spinner("x", stream=FakeStream(tty=True)).active() is True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_frames_are_braille():
|
|
50
|
+
assert spin._FRAMES == "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_context_manager_returns_self():
|
|
54
|
+
s = FakeStream(tty=False)
|
|
55
|
+
sp = spin.Spinner("x", stream=s)
|
|
56
|
+
assert sp.__enter__() is sp
|
|
57
|
+
assert sp.__exit__(None, None, None) is None # doesn't suppress exceptions
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_tty_run_writes_and_clears():
|
|
61
|
+
# exercise the animated path: wait (bounded) for the thread's first frame
|
|
62
|
+
import time
|
|
63
|
+
s = FakeStream(tty=True)
|
|
64
|
+
with spin.Spinner("go", stream=s):
|
|
65
|
+
for _ in range(50):
|
|
66
|
+
if s.getvalue():
|
|
67
|
+
break
|
|
68
|
+
time.sleep(0.02)
|
|
69
|
+
out = s.getvalue()
|
|
70
|
+
assert "\r" in out # in-place redraw
|
|
71
|
+
assert "go" in out # the label was shown
|
|
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.38 → boost_skill_cli-1.0.40}/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
|
{boost_skill_cli-1.0.38 → boost_skill_cli-1.0.40}/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
|