boost-skill-cli 1.0.22__tar.gz → 1.0.24__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.
Files changed (105) hide show
  1. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/info.py +19 -0
  4. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/output.py +6 -0
  5. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  6. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/design-roadmap.html +1 -1
  7. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/roadmap.html +141 -1
  8. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_info.py +4 -0
  9. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_output.py +18 -0
  10. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/.gitignore +0 -0
  11. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/CLAUDE.md +0 -0
  12. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/CONTRIBUTING.md +0 -0
  13. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/LICENSE +0 -0
  14. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/MANIFEST.in +0 -0
  15. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/Makefile +0 -0
  16. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/README.md +0 -0
  17. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/SECURITY.md +0 -0
  18. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost +0 -0
  19. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/__init__.py +0 -0
  20. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/__main__.py +0 -0
  21. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/cli.py +0 -0
  22. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/__init__.py +0 -0
  23. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/bmad.py +0 -0
  24. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/configuration.py +0 -0
  25. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/discovery.py +0 -0
  26. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/hooks.py +0 -0
  27. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/intelligence.py +0 -0
  28. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/pkg.py +0 -0
  29. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/quality.py +0 -0
  30. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/taps.py +0 -0
  31. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/commands/team.py +0 -0
  32. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/__init__.py +0 -0
  33. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/agents.py +0 -0
  34. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/ai.py +0 -0
  35. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/catalog.py +0 -0
  36. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/claude_settings.py +0 -0
  37. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/config.py +0 -0
  38. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/dense.py +0 -0
  39. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/embed.py +0 -0
  40. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/frontmatter.py +0 -0
  41. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/gitutil.py +0 -0
  42. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/journal.py +0 -0
  43. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/lockfile.py +0 -0
  44. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/logs.py +0 -0
  45. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/paths.py +0 -0
  46. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/policy.py +0 -0
  47. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/rag.py +0 -0
  48. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/registry.py +0 -0
  49. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/store.py +0 -0
  50. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/core/util.py +0 -0
  51. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/data/registries.json +0 -0
  52. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_cli/errors.py +0 -0
  53. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/SOURCES.txt +0 -0
  54. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  55. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  56. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/requires.txt +0 -0
  57. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/boost_skill_cli.egg-info/top_level.txt +0 -0
  58. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/.claude/settings.local.json +0 -0
  59. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/DEBUGGING.md +0 -0
  60. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/demo.gif +0 -0
  61. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/demo.tape +0 -0
  62. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/index.html +0 -0
  63. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/docs/rag-architecture.md +0 -0
  64. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/pyproject.toml +0 -0
  65. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/scripts/build_registries.py +0 -0
  66. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/scripts/mutation_gate.py +0 -0
  67. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/setup.cfg +0 -0
  68. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/style/README.md +0 -0
  69. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/style/boost.css +0 -0
  70. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/style/boost.js +0 -0
  71. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/style/demo.html +0 -0
  72. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/conftest.py +0 -0
  73. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_bmad.py +0 -0
  74. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_configuration.py +0 -0
  75. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_discovery.py +0 -0
  76. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_hooks.py +0 -0
  77. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_intelligence.py +0 -0
  78. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_pkg.py +0 -0
  79. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_quality.py +0 -0
  80. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_taps.py +0 -0
  81. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_cli_team.py +0 -0
  82. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/functional/test_everyday_loop.py +0 -0
  83. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/make_fixture.py +0 -0
  84. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/smoke.sh +0 -0
  85. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_agents.py +0 -0
  86. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_ai.py +0 -0
  87. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_catalog.py +0 -0
  88. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_claude_settings.py +0 -0
  89. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_config.py +0 -0
  90. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_dense.py +0 -0
  91. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_embed.py +0 -0
  92. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_errors_and_cli_table.py +0 -0
  93. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_frontmatter.py +0 -0
  94. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_gitutil.py +0 -0
  95. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_journal.py +0 -0
  96. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_lockfile.py +0 -0
  97. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_logs.py +0 -0
  98. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_mutation_hardening.py +0 -0
  99. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_paths.py +0 -0
  100. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_policy.py +0 -0
  101. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_rag.py +0 -0
  102. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_registry.py +0 -0
  103. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_store.py +0 -0
  104. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_util.py +0 -0
  105. {boost_skill_cli-1.0.22 → boost_skill_cli-1.0.24}/tests/unit/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.22
3
+ Version: 1.0.24
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -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'
22
- __version_tuple__ = version_tuple = (1, 0, 22)
21
+ __version__ = version = '1.0.24'
22
+ __version_tuple__ = version_tuple = (1, 0, 24)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -175,6 +175,25 @@ def cmd_info(argv):
175
175
  return 0
176
176
 
177
177
  out.heading(name)
178
+ # Identity-card badges: a scannable status strip beneath the name, echoing
179
+ # the web .badge pills. The detailed kv rows below still carry the specifics.
180
+ badges = []
181
+ if lock:
182
+ badges.append(out.badge("installed", "green"))
183
+ if lock.get("pinned"):
184
+ badges.append(out.badge("pinned", "yellow"))
185
+ if lock.get("quarantined"):
186
+ badges.append(out.badge("quarantined", "pink"))
187
+ latest = str((cat or {}).get("version") or "")
188
+ if cat and latest != str(lock.get("version", "?")):
189
+ badges.append(out.badge("update available", "yellow"))
190
+ else:
191
+ badges.append(out.badge("not installed", "cyan"))
192
+ tapname = (lock or cat or {}).get("tap")
193
+ if tapname:
194
+ badges.append(out.badge(str(tapname), "violet"))
195
+ if badges:
196
+ out.info(" ".join(badges))
178
197
  if desc:
179
198
  lines = textwrap.wrap(desc, width=62)
180
199
  out.kv("description", lines[0])
@@ -177,6 +177,12 @@ def truncate(text: str, width: int, ellipsis: str = "…") -> str:
177
177
  return text[:width - len(ellipsis)] + ellipsis
178
178
 
179
179
 
180
+ def badge(label: str, hue: str = "cyan") -> str:
181
+ """A compact status pill for identity cards — an Aurora-tinted [label]
182
+ (plain under NO_COLOR), echoing the web design system's .badge pills."""
183
+ return aurora("[" + label + "]", hue)
184
+
185
+
180
186
  def kv(key: str, value: str, width: int = 14) -> None:
181
187
  print(" " + c(key.ljust(width), DIM) + str(value))
182
188
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.22
3
+ Version: 1.0.24
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -404,7 +404,7 @@
404
404
  </article>
405
405
 
406
406
  <article class="ritem" data-track="commands" data-impact="low">
407
- <div class="ritem-top"><span class="rid">BOOST-D17</span><span class="rstatus proposed">Proposed</span></div>
407
+ <div class="ritem-top"><span class="rid">BOOST-D17</span><span class="rstatus done">Shipped</span></div>
408
408
  <h4><code>list</code> polish — chips &amp; aligned counts</h4>
409
409
  <p><code>list</code> already uses a nice <code>·</code> agent separator; take it further. Color the agent names as small chips, right-align the count footer with tabular figures, and add a dim header rule so the table reads as a designed object rather than raw columns.</p>
410
410
  <div class="rmeta"><span class="m-cat">commands</span><span>Complexity S</span><span class="m-imp low">Impact Low</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>8</b><span>Code-health finds</span></div>
119
+ <div class="stat"><b>16</b><span>Loop finds</span></div>
120
120
  </div>
121
121
  </section>
122
122
 
@@ -456,6 +456,146 @@
456
456
  </div>
457
457
  </section>
458
458
 
459
+ <!-- ============ PIPELINE & SUPPLY-CHAIN INTEGRITY ============ -->
460
+ <section class="block reveal" id="pipeline">
461
+ <div class="block-head">
462
+ <h2>Pipeline &amp; supply-chain integrity</h2>
463
+ <span class="count">// planned · free tooling to secure the CI/CD path itself</span>
464
+ <span class="rule"></span>
465
+ </div>
466
+ <div class="rgrid">
467
+
468
+ <article class="cap rcard">
469
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Security · CI/CD</span></div>
470
+ <h3>Workflow SAST — <code>zizmor</code></h3>
471
+ <p>boost's four workflows embed <code>github-script</code> JavaScript and
472
+ shell and drive a Trusted-Publisher release — a rich attack surface.
473
+ <code>zizmor</code> statically flags template injection, unpinned
474
+ actions, over-broad <code>GITHUB_TOKEN</code> permissions and dangerous
475
+ triggers. The one tool that audits the automation that ships every
476
+ other fix.</p>
477
+ <div class="meta">
478
+ <span class="m">Complexity <b>S</b></span>
479
+ <span class="m hi">Impact <b>High</b></span>
480
+ <span class="m">Wow <b class="wow">★★★★★</b></span>
481
+ <span class="m">pipx-run</span>
482
+ </div>
483
+ </article>
484
+
485
+ <article class="cap rcard">
486
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · CI/CD</span></div>
487
+ <h3>Workflow linting — <code>actionlint</code></h3>
488
+ <p>Catches GitHub Actions YAML bugs before they fail a live release:
489
+ malformed <code>${{ }}</code> expressions, deprecated syntax, and
490
+ shellcheck run over every <code>run:</code> block. Cheap insurance for a
491
+ repo whose release is fully automated — a broken workflow is a broken
492
+ publish.</p>
493
+ <div class="meta">
494
+ <span class="m">Complexity <b>S</b></span>
495
+ <span class="m">Impact <b>Med</b></span>
496
+ <span class="m">Wow <b class="wow">★★★</b></span>
497
+ <span class="m">shellcheck built in</span>
498
+ </div>
499
+ </article>
500
+
501
+ <article class="cap rcard">
502
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Security · Supply chain</span></div>
503
+ <h3>Build provenance — SLSA attestations</h3>
504
+ <p><code>actions/attest-build-provenance</code> emits a cryptographically
505
+ signed, verifiable record of <em>which workflow built which wheel from
506
+ which commit</em>, layered on top of the existing PyPI Trusted
507
+ Publishing. Consumers can <code>gh attestation verify</code> the
508
+ artifact they install — provenance without a paid signing service.</p>
509
+ <div class="meta">
510
+ <span class="m">Complexity <b>S</b></span>
511
+ <span class="m">Impact <b>Med</b></span>
512
+ <span class="m">Wow <b class="wow">★★★★</b></span>
513
+ <span class="m">SLSA build L2</span>
514
+ </div>
515
+ </article>
516
+
517
+ <article class="cap rcard">
518
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Security · Supply chain</span></div>
519
+ <h3>SBOM on every release — CycloneDX / Syft</h3>
520
+ <p>Generate a CycloneDX SBOM with the free <code>anchore/sbom-action</code>
521
+ and attach it to each GitHub Release, so downstreams can inventory and
522
+ scan exactly what boost is built from. Modest today (boost is close to
523
+ stdlib-only) but it grows in value as the optional <code>[rag]</code>
524
+ extras pull in real dependencies.</p>
525
+ <div class="meta">
526
+ <span class="m">Complexity <b>S</b></span>
527
+ <span class="m">Impact <b>Med</b></span>
528
+ <span class="m">Wow <b class="wow">★★★</b></span>
529
+ <span class="m">feeds osv-scanner</span>
530
+ </div>
531
+ </article>
532
+
533
+ <article class="cap rcard">
534
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Security · Vuln</span></div>
535
+ <h3>SBOM-aware scanning — <code>osv-scanner</code></h3>
536
+ <p>Google's <code>osv-scanner</code> cross-checks a lockfile or the SBOM
537
+ above against the OSV database, with broader ecosystem coverage than a
538
+ single-language audit. The SBOM-driven complement to <code>pip-audit</code>:
539
+ one scans the resolved env, the other scans the published manifest.</p>
540
+ <div class="meta">
541
+ <span class="m">Complexity <b>S</b></span>
542
+ <span class="m">Impact <b>Med</b></span>
543
+ <span class="m">Wow <b class="wow">★★</b></span>
544
+ <span class="m">OSV-backed</span>
545
+ </div>
546
+ </article>
547
+
548
+ <article class="cap rcard">
549
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Testing · Type</span></div>
550
+ <h3>Second type checker — <code>pyright</code></h3>
551
+ <p>Run Microsoft's <code>pyright</code> alongside mypy. Its independent
552
+ inference catches <code>None</code>-flow and narrowing bugs the current
553
+ mypy config lets slide, and it's the same engine most editors use — so
554
+ CI enforces what contributors already see. Two type checkers rarely
555
+ agree on <em>nothing</em>.</p>
556
+ <div class="meta">
557
+ <span class="m">Complexity <b>M</b></span>
558
+ <span class="m">Impact <b>Med</b></span>
559
+ <span class="m">Wow <b class="wow">★★★</b></span>
560
+ <span class="m">editor-parity</span>
561
+ </div>
562
+ </article>
563
+
564
+ <article class="cap rcard">
565
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Quality · Smell</span></div>
566
+ <h3>Widen the ruff rule surface — <code>B·SIM·C4·PERF·RUF</code></h3>
567
+ <p>Beyond the <code>S</code> security family (round 1), enable
568
+ flake8-bugbear (<code>B</code>), simplify (<code>SIM</code>),
569
+ comprehensions (<code>C4</code>), perflint (<code>PERF</code>) and
570
+ Ruff-native (<code>RUF</code>) rules — bug, readability and performance
571
+ smells caught at zero new-tool cost since ruff already runs in the lint
572
+ gate.</p>
573
+ <div class="meta">
574
+ <span class="m">Complexity <b>S</b></span>
575
+ <span class="m">Impact <b>Med</b></span>
576
+ <span class="m">Wow <b class="wow">★★★</b></span>
577
+ <span class="m">0 new deps</span>
578
+ </div>
579
+ </article>
580
+
581
+ <article class="cap rcard">
582
+ <div class="head"><span class="pill planned">Planned</span><span class="cat">Testing · Gap</span></div>
583
+ <h3>Patch-coverage gate — <code>diff-cover</code></h3>
584
+ <p>Enforce coverage on the <em>changed lines</em> of each PR — no external
585
+ service needed, it reads the same <code>coverage.xml</code> the suite
586
+ already emits. Pairs with the 80% project gate so new code can't quietly
587
+ ride in under-tested behind an already-high overall number.</p>
588
+ <div class="meta">
589
+ <span class="m">Complexity <b>S</b></span>
590
+ <span class="m">Impact <b>Med</b></span>
591
+ <span class="m">Wow <b class="wow">★★</b></span>
592
+ <span class="m">self-hosted</span>
593
+ </div>
594
+ </article>
595
+
596
+ </div>
597
+ </section>
598
+
459
599
  <footer>
460
600
  <p>Maintained by the boost quality loop · themed with
461
601
  <a href="../style/boost.css">style/boost.css</a> ·
@@ -83,6 +83,9 @@ class TestInfo:
83
83
  assert "claude-code, windsurf, cursor" in r.out
84
84
  assert re.search(r"pinned\s+no", r.out)
85
85
  assert re.search(r"quarantined\s+no", r.out)
86
+ # D17: identity-card badges beneath the name
87
+ assert "[installed]" in r.out
88
+ assert "[fixture-tap]" in r.out
86
89
 
87
90
  def test_tap_only_skill(self, boost, tapped):
88
91
  r = boost("info", "jira-integration")
@@ -90,6 +93,7 @@ class TestInfo:
90
93
  assert re.search(r"tap\s+fixture-tap", r.out)
91
94
  assert re.search(r"source\s+skills/jira-integration", r.out)
92
95
  assert "~/.agents/skills" not in r.out # no store line
96
+ assert "[not installed]" in r.out # D17 badge for tap-only
93
97
  assert re.search(r"quality\s+\d+/100", r.out)
94
98
 
95
99
  def test_json_pure(self, boost, installed):
@@ -278,6 +278,24 @@ class TestTruncate:
278
278
  assert output.truncate("abcdef", 1) == "…"
279
279
 
280
280
 
281
+ class TestBadge:
282
+ def test_plain_when_no_color(self, monkeypatch):
283
+ monkeypatch.setenv("NO_COLOR", "1")
284
+ assert output.badge("installed", "green") == "[installed]"
285
+
286
+ def test_default_hue_is_cyan(self, monkeypatch):
287
+ monkeypatch.setenv("COLORTERM", "truecolor")
288
+ monkeypatch.setenv("CLICOLOR_FORCE", "1")
289
+ assert output.badge("x") == "\033[38;2;34;211;238m[x]\033[0m"
290
+
291
+ def test_truecolor_wraps_label_in_brackets(self, monkeypatch):
292
+ monkeypatch.setenv("COLORTERM", "truecolor")
293
+ monkeypatch.setenv("CLICOLOR_FORCE", "1")
294
+ # green #4ade80
295
+ assert output.badge("installed", "green") == (
296
+ "\033[38;2;74;222;128m[installed]\033[0m")
297
+
298
+
281
299
  class TestHelpers:
282
300
  @pytest.fixture(autouse=True)
283
301
  def plain(self, monkeypatch):
File without changes