boost-skill-cli 1.0.32__tar.gz → 1.0.34__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 (107) hide show
  1. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/_version.py +2 -2
  3. boost_skill_cli-1.0.34/boost_cli/cliparse.py +31 -0
  4. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/bmad.py +2 -2
  5. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/configuration.py +11 -11
  6. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/discovery.py +10 -9
  7. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/hooks.py +2 -2
  8. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/info.py +11 -11
  9. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/intelligence.py +9 -9
  10. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/pkg.py +13 -13
  11. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/quality.py +15 -15
  12. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/taps.py +5 -4
  13. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/team.py +7 -7
  14. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  15. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
  16. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/design-roadmap.html +2 -2
  17. boost_skill_cli-1.0.34/tests/unit/test_cliparse.py +43 -0
  18. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/.gitignore +0 -0
  19. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/CLAUDE.md +0 -0
  20. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/CONTRIBUTING.md +0 -0
  21. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/LICENSE +0 -0
  22. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/MANIFEST.in +0 -0
  23. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/Makefile +0 -0
  24. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/README.md +0 -0
  25. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/SECURITY.md +0 -0
  26. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost +0 -0
  27. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/__init__.py +0 -0
  28. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/__main__.py +0 -0
  29. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/cli.py +0 -0
  30. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/commands/__init__.py +0 -0
  31. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/__init__.py +0 -0
  32. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/agents.py +0 -0
  33. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/ai.py +0 -0
  34. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/catalog.py +0 -0
  35. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/claude_settings.py +0 -0
  36. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/config.py +0 -0
  37. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/dense.py +0 -0
  38. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/embed.py +0 -0
  39. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/frontmatter.py +0 -0
  40. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/gitutil.py +0 -0
  41. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/journal.py +0 -0
  42. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/lockfile.py +0 -0
  43. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/logs.py +0 -0
  44. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/output.py +0 -0
  45. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/paths.py +0 -0
  46. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/policy.py +0 -0
  47. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/rag.py +0 -0
  48. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/registry.py +0 -0
  49. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/store.py +0 -0
  50. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/core/util.py +0 -0
  51. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/data/registries.json +0 -0
  52. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_cli/errors.py +0 -0
  53. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  54. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  55. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/requires.txt +0 -0
  56. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/boost_skill_cli.egg-info/top_level.txt +0 -0
  57. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/.claude/settings.local.json +0 -0
  58. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/DEBUGGING.md +0 -0
  59. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/demo.gif +0 -0
  60. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/demo.tape +0 -0
  61. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/index.html +0 -0
  62. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/rag-architecture.md +0 -0
  63. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/docs/roadmap.html +0 -0
  64. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/pyproject.toml +0 -0
  65. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/scripts/build_registries.py +0 -0
  66. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/scripts/mutation_gate.py +0 -0
  67. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/setup.cfg +0 -0
  68. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/style/README.md +0 -0
  69. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/style/boost.css +0 -0
  70. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/style/boost.js +0 -0
  71. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/style/demo.html +0 -0
  72. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/conftest.py +0 -0
  73. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_bmad.py +0 -0
  74. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_configuration.py +0 -0
  75. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_discovery.py +0 -0
  76. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_hooks.py +0 -0
  77. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_info.py +0 -0
  78. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_intelligence.py +0 -0
  79. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_pkg.py +0 -0
  80. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_quality.py +0 -0
  81. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_taps.py +0 -0
  82. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_cli_team.py +0 -0
  83. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/functional/test_everyday_loop.py +0 -0
  84. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/make_fixture.py +0 -0
  85. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/smoke.sh +0 -0
  86. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_agents.py +0 -0
  87. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_ai.py +0 -0
  88. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_catalog.py +0 -0
  89. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_claude_settings.py +0 -0
  90. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_config.py +0 -0
  91. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_dense.py +0 -0
  92. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_embed.py +0 -0
  93. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_errors_and_cli_table.py +0 -0
  94. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_frontmatter.py +0 -0
  95. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_gitutil.py +0 -0
  96. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_journal.py +0 -0
  97. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_lockfile.py +0 -0
  98. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_logs.py +0 -0
  99. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_mutation_hardening.py +0 -0
  100. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_output.py +0 -0
  101. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_paths.py +0 -0
  102. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_policy.py +0 -0
  103. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_rag.py +0 -0
  104. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_registry.py +0 -0
  105. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_store.py +0 -0
  106. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/tests/unit/test_util.py +0 -0
  107. {boost_skill_cli-1.0.32 → boost_skill_cli-1.0.34}/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.32
3
+ Version: 1.0.34
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.32'
22
- __version_tuple__ = version_tuple = (1, 0, 32)
21
+ __version__ = version = '1.0.34'
22
+ __version_tuple__ = version_tuple = (1, 0, 34)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,31 @@
1
+ """A branded ArgumentParser.
2
+
3
+ Argparse's default failure output is a raw, unstyled ``usage:`` block with a
4
+ bare ``prog: error: …`` line — nothing like boost's branded top-level dispatch
5
+ (which routes through :func:`output.err` and offers a "did you mean"). This
6
+ subclass routes a parser's own errors through the same Aurora output layer, so
7
+ a wrong invocation looks as designed as a right one.
8
+
9
+ Adopt it via :func:`parser` in place of ``argparse.ArgumentParser``. Sub-parsers
10
+ created with ``add_subparsers()`` inherit this class automatically, so a single
11
+ top-level swap brands a command's whole tree.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import sys
17
+
18
+ from .core import output as out
19
+
20
+
21
+ class BoostArgumentParser(argparse.ArgumentParser):
22
+ def error(self, message: str): # noqa: D401 - argparse hook
23
+ """Print a branded error + dimmed usage, then exit 2 (argparse's code)."""
24
+ out.err(message)
25
+ sys.stderr.write(out.c(self.format_usage(), out.DIM))
26
+ self.exit(2)
27
+
28
+
29
+ def parser(*args, **kwargs) -> BoostArgumentParser:
30
+ """Drop-in replacement for ``argparse.ArgumentParser(...)``."""
31
+ return BoostArgumentParser(*args, **kwargs)
@@ -18,7 +18,6 @@ runtime is per-project (`boost bmad init`).
18
18
  """
19
19
  from __future__ import annotations
20
20
 
21
- import argparse
22
21
  import getpass
23
22
  import json
24
23
  import os
@@ -29,6 +28,7 @@ import subprocess
29
28
  import tempfile
30
29
  from pathlib import Path
31
30
 
31
+ from .. import cliparse
32
32
  from ..core import claude_settings as cs
33
33
  from ..core import journal
34
34
  from ..core import output as out
@@ -64,7 +64,7 @@ _ACTIONS = ("install", "init", "startup", "orient", "uninstall",
64
64
 
65
65
 
66
66
  def cmd_bmad(argv) -> int:
67
- p = argparse.ArgumentParser(
67
+ p = cliparse.parser(
68
68
  prog="boost bmad",
69
69
  description="Install & manage the BMAD Method (scope-aware, toggleable)")
70
70
  p.add_argument("action", choices=_ACTIONS, help=" | ".join(_ACTIONS))
@@ -2,7 +2,6 @@
2
2
  completions, schedule, serve, mcp, self-update."""
3
3
  from __future__ import annotations
4
4
 
5
- import argparse
6
5
  import errno
7
6
  import getpass
8
7
  import html
@@ -18,6 +17,7 @@ from datetime import datetime, timedelta
18
17
  from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
19
18
  from pathlib import Path
20
19
 
20
+ from .. import cliparse
21
21
  from .. import __version__
22
22
  from ..core import agents, catalog, config, frontmatter, gitutil, journal
23
23
  from ..core import lockfile, paths, policy, rag, registry, store, util
@@ -47,7 +47,7 @@ def _user() -> str:
47
47
 
48
48
  def cmd_config(argv) -> int:
49
49
  """boost config [list|get KEY|set KEY VALUE|unset KEY] [--json]"""
50
- p = argparse.ArgumentParser(
50
+ p = cliparse.parser(
51
51
  prog="boost config",
52
52
  description="Display or modify boost configuration")
53
53
  p.add_argument("action", nargs="?", default="list",
@@ -112,7 +112,7 @@ def cmd_config(argv) -> int:
112
112
 
113
113
  def cmd_clean(argv) -> int:
114
114
  """boost clean [--dry-run] [--deep]"""
115
- p = argparse.ArgumentParser(
115
+ p = cliparse.parser(
116
116
  prog="boost clean",
117
117
  description="Clear stale caches & broken symlinks")
118
118
  p.add_argument("--dry-run", action="store_true",
@@ -215,7 +215,7 @@ TODO: a concrete input/output example
215
215
 
216
216
  def cmd_create(argv) -> int:
217
217
  """boost create NAME [--description D] [--dir DIR] [--install]"""
218
- p = argparse.ArgumentParser(
218
+ p = cliparse.parser(
219
219
  prog="boost create",
220
220
  description="Scaffold a new skill from a template")
221
221
  p.add_argument("name", help="skill name (slugified)")
@@ -271,7 +271,7 @@ def _parse_policy_value(key: str, raw: str):
271
271
 
272
272
  def cmd_policy(argv) -> int:
273
273
  """boost policy [list|set KEY VALUE|unset KEY|check] [--json]"""
274
- p = argparse.ArgumentParser(
274
+ p = cliparse.parser(
275
275
  prog="boost policy",
276
276
  description="Manage & enforce skill governance policies")
277
277
  p.add_argument("action", nargs="?", default="list",
@@ -399,7 +399,7 @@ jobs:
399
399
 
400
400
  def cmd_onboard(argv) -> int:
401
401
  """boost onboard [--repo DIR] [--pr] [--dry-run]"""
402
- p = argparse.ArgumentParser(
402
+ p = cliparse.parser(
403
403
  prog="boost onboard",
404
404
  description="Add skill-tracker telemetry to a repo & open a PR")
405
405
  p.add_argument("--repo", default=".", help="repository directory (default: .)")
@@ -481,7 +481,7 @@ def _sq(s: str) -> str:
481
481
 
482
482
  def cmd_completions(argv) -> int:
483
483
  """boost completions [bash|zsh|fish]"""
484
- p = argparse.ArgumentParser(
484
+ p = cliparse.parser(
485
485
  prog="boost completions",
486
486
  description="Generate shell tab-completion scripts")
487
487
  p.add_argument("shell", nargs="?", choices=("bash", "zsh", "fish"),
@@ -597,7 +597,7 @@ def _interval_label(seconds) -> str:
597
597
 
598
598
  def cmd_schedule(argv) -> int:
599
599
  """boost schedule [status|enable [--interval 6h|12h|daily]|disable]"""
600
- p = argparse.ArgumentParser(
600
+ p = cliparse.parser(
601
601
  prog="boost schedule",
602
602
  description="Manage automatic skill-sync scheduling")
603
603
  p.add_argument("action", nargs="?", default="status",
@@ -832,7 +832,7 @@ class _CatalogHandler(BaseHTTPRequestHandler):
832
832
 
833
833
  def cmd_serve(argv) -> int:
834
834
  """boost serve [--port N] [--host H]"""
835
- p = argparse.ArgumentParser(
835
+ p = cliparse.parser(
836
836
  prog="boost serve",
837
837
  description="Serve the skill catalog over HTTP (port 8787)")
838
838
  p.add_argument("--port", type=int,
@@ -1029,7 +1029,7 @@ def _mcp_serve_stdio() -> int:
1029
1029
 
1030
1030
  def cmd_mcp(argv) -> int:
1031
1031
  """boost mcp [register|unregister] [--stdio]"""
1032
- p = argparse.ArgumentParser(
1032
+ p = cliparse.parser(
1033
1033
  prog="boost mcp",
1034
1034
  description="Register boost as an MCP server for Claude Code")
1035
1035
  p.add_argument("action", nargs="?", default="register",
@@ -1075,7 +1075,7 @@ def cmd_mcp(argv) -> int:
1075
1075
 
1076
1076
  def cmd_self_update(argv) -> int:
1077
1077
  """boost self-update"""
1078
- p = argparse.ArgumentParser(
1078
+ p = cliparse.parser(
1079
1079
  prog="boost self-update",
1080
1080
  description="Update boost itself to the latest version")
1081
1081
  p.parse_args(argv)
@@ -15,6 +15,7 @@ import sys
15
15
  import time
16
16
  from pathlib import Path
17
17
 
18
+ from .. import cliparse
18
19
  from ..core import agents, ai, catalog, dense, embed, gitutil, journal, lockfile, paths, rag, registry, store, util
19
20
  from ..core import output as out
20
21
  from ..errors import BoostError
@@ -169,7 +170,7 @@ def _ai_rank(query: str, scored):
169
170
 
170
171
  def cmd_search(argv):
171
172
  """Search the tap catalogs, optionally AI-reranked with --smart."""
172
- p = argparse.ArgumentParser(
173
+ p = cliparse.parser(
173
174
  prog="boost search",
174
175
  description="Search skills across tap registries (AI-ranked)")
175
176
  p.add_argument("query", nargs="+", help="search terms")
@@ -233,7 +234,7 @@ def cmd_search(argv):
233
234
 
234
235
  def cmd_reindex(argv):
235
236
  """Build/refresh the full-content (RAG) search index over tapped items."""
236
- p = argparse.ArgumentParser(
237
+ p = cliparse.parser(
237
238
  prog="boost reindex",
238
239
  description="Build or refresh the full-content search index")
239
240
  p.add_argument("--force", action="store_true",
@@ -282,7 +283,7 @@ def _reindex_dense(force):
282
283
 
283
284
  def cmd_index(argv):
284
285
  """Build ~/.boost/cache/discovery.json via `gh api` code search."""
285
- p = argparse.ArgumentParser(
286
+ p = cliparse.parser(
286
287
  prog="boost index",
287
288
  description="Build the discovery registry via GitHub Code Search")
288
289
  p.add_argument("--limit", type=_positive_int, default=300,
@@ -345,7 +346,7 @@ def cmd_index(argv):
345
346
 
346
347
  def cmd_discover(argv):
347
348
  """Browse/filter the GitHub-wide index built by `boost index`."""
348
- p = argparse.ArgumentParser(
349
+ p = cliparse.parser(
349
350
  prog="boost discover",
350
351
  description="Browse & search the GitHub-wide skill discovery index")
351
352
  p.add_argument("query", nargs="*", help="filter terms (repo/path substring)")
@@ -414,7 +415,7 @@ def _ai_picks(stack: dict, cands):
414
415
 
415
416
  def cmd_recommend(argv):
416
417
  """Match the detected tech stack against the catalog."""
417
- p = argparse.ArgumentParser(
418
+ p = cliparse.parser(
418
419
  prog="boost recommend",
419
420
  description="Suggest skills based on your project's tech stack")
420
421
  p.add_argument("--path", default=".", help="project directory (default: cwd)")
@@ -564,7 +565,7 @@ def _browse_tui(curses, entries):
564
565
 
565
566
  def cmd_browse(argv):
566
567
  """Full-screen fuzzy browser over every catalog entry."""
567
- p = argparse.ArgumentParser(
568
+ p = cliparse.parser(
568
569
  prog="boost browse",
569
570
  description="Interactive full-screen TUI with fuzzy search")
570
571
  p.parse_args(argv)
@@ -594,7 +595,7 @@ def cmd_browse(argv):
594
595
 
595
596
  def cmd_trending(argv):
596
597
  """Rank skills by local install events from the journal."""
597
- p = argparse.ArgumentParser(
598
+ p = cliparse.parser(
598
599
  prog="boost trending",
599
600
  description="Show trending skills by install count")
600
601
  p.add_argument("--limit", type=_positive_int, default=10,
@@ -630,7 +631,7 @@ def cmd_trending(argv):
630
631
 
631
632
  def cmd_stats(argv):
632
633
  """Lock-file, journal, and upstream stats for one skill."""
633
- p = argparse.ArgumentParser(
634
+ p = cliparse.parser(
634
635
  prog="boost stats",
635
636
  description="Install statistics & trend for a single skill")
636
637
  p.add_argument("name", help="skill name")
@@ -696,7 +697,7 @@ def cmd_stats(argv):
696
697
 
697
698
  def cmd_count(argv):
698
699
  """One-line inventory: installed / available / taps / discovery index."""
699
- p = argparse.ArgumentParser(
700
+ p = cliparse.parser(
700
701
  prog="boost count",
701
702
  description="Quick summary of installed / available / taps")
702
703
  p.add_argument("--json", action="store_true", dest="as_json",
@@ -10,8 +10,8 @@ are left untouched. See core/claude_settings.py.
10
10
  """
11
11
  from __future__ import annotations
12
12
 
13
- import argparse
14
13
 
14
+ from .. import cliparse
15
15
  from ..core import claude_settings as cs
16
16
  from ..core import journal
17
17
  from ..core import output as out
@@ -19,7 +19,7 @@ from ..errors import BoostError
19
19
 
20
20
 
21
21
  def cmd_hooks(argv) -> int:
22
- p = argparse.ArgumentParser(
22
+ p = cliparse.parser(
23
23
  prog="boost hooks",
24
24
  description="Manage Claude Code hooks (scope-aware) in settings.json")
25
25
  p.add_argument("action", choices=("add", "remove", "list"),
@@ -5,7 +5,6 @@ Read-mostly views over the lock file, the canonical store, and tap catalogs.
5
5
  """
6
6
  from __future__ import annotations
7
7
 
8
- import argparse
9
8
  import json
10
9
  import os
11
10
  import re
@@ -16,6 +15,7 @@ import textwrap
16
15
  import webbrowser
17
16
  from pathlib import Path
18
17
 
18
+ from .. import cliparse
19
19
  from ..core import ai, catalog, frontmatter, gitutil, journal, lockfile, logs, paths, registry, store, util
20
20
  from ..core import output as out
21
21
  from ..errors import BoostError
@@ -101,7 +101,7 @@ def _print_wrapped(text: str) -> None:
101
101
  # ---------------------------------------------------------------- commands
102
102
 
103
103
  def cmd_list(argv):
104
- ap = argparse.ArgumentParser(prog="boost list",
104
+ ap = cliparse.parser(prog="boost list",
105
105
  description="List installed skills")
106
106
  ap.add_argument("--tag", help="only show skills carrying this tag")
107
107
  ap.add_argument("--json", action="store_true", help="machine-readable output")
@@ -136,7 +136,7 @@ def cmd_list(argv):
136
136
 
137
137
 
138
138
  def cmd_info(argv):
139
- ap = argparse.ArgumentParser(prog="boost info",
139
+ ap = cliparse.parser(prog="boost info",
140
140
  description="Show detailed info about a skill")
141
141
  ap.add_argument("name")
142
142
  ap.add_argument("--json", action="store_true", help="machine-readable output")
@@ -242,7 +242,7 @@ def cmd_info(argv):
242
242
 
243
243
 
244
244
  def cmd_cat(argv):
245
- ap = argparse.ArgumentParser(prog="boost cat",
245
+ ap = cliparse.parser(prog="boost cat",
246
246
  description="Print a skill or rule's contents")
247
247
  ap.add_argument("name")
248
248
  ap.add_argument("--raw", action="store_true", help="no styling even on a TTY")
@@ -265,7 +265,7 @@ def cmd_cat(argv):
265
265
 
266
266
 
267
267
  def cmd_edit(argv):
268
- ap = argparse.ArgumentParser(prog="boost edit",
268
+ ap = cliparse.parser(prog="boost edit",
269
269
  description="Open a skill's SKILL.md in your editor")
270
270
  ap.add_argument("name")
271
271
  args = ap.parse_args(argv)
@@ -341,7 +341,7 @@ def _render_markdown(body: str) -> None:
341
341
 
342
342
 
343
343
  def cmd_preview(argv):
344
- ap = argparse.ArgumentParser(prog="boost preview",
344
+ ap = cliparse.parser(prog="boost preview",
345
345
  description="Render a SKILL.md with rich formatting")
346
346
  ap.add_argument("name")
347
347
  args = ap.parse_args(argv)
@@ -356,7 +356,7 @@ def cmd_preview(argv):
356
356
 
357
357
 
358
358
  def cmd_explain(argv):
359
- ap = argparse.ArgumentParser(prog="boost explain",
359
+ ap = cliparse.parser(prog="boost explain",
360
360
  description="Explain what a skill does in plain English")
361
361
  ap.add_argument("name")
362
362
  args = ap.parse_args(argv)
@@ -432,7 +432,7 @@ def _show_crashes(limit):
432
432
 
433
433
 
434
434
  def cmd_log(argv):
435
- ap = argparse.ArgumentParser(prog="boost log",
435
+ ap = cliparse.parser(prog="boost log",
436
436
  description="Git log for a skill, or boost's activity log")
437
437
  ap.add_argument("name", nargs="?", help="skill to show upstream history for")
438
438
  ap.add_argument("-n", "--limit", type=int, default=20, metavar="N",
@@ -487,7 +487,7 @@ def cmd_log(argv):
487
487
 
488
488
 
489
489
  def cmd_home(argv):
490
- ap = argparse.ArgumentParser(prog="boost home",
490
+ ap = cliparse.parser(prog="boost home",
491
491
  description="Open a skill's GitHub page in the browser")
492
492
  ap.add_argument("name")
493
493
  ap.add_argument("--print", dest="print_only", action="store_true",
@@ -517,7 +517,7 @@ def cmd_home(argv):
517
517
 
518
518
 
519
519
  def cmd_deps(argv):
520
- ap = argparse.ArgumentParser(prog="boost deps",
520
+ ap = cliparse.parser(prog="boost deps",
521
521
  description="Show dependency & conflict relationships")
522
522
  ap.add_argument("name", nargs="?", help="skill to inspect (default: check all installed)")
523
523
  ap.add_argument("--json", action="store_true", help="machine-readable output")
@@ -587,7 +587,7 @@ def cmd_deps(argv):
587
587
 
588
588
 
589
589
  def cmd_tag(argv):
590
- ap = argparse.ArgumentParser(prog="boost tag",
590
+ ap = cliparse.parser(prog="boost tag",
591
591
  description="Custom labels for organizing skills")
592
592
  ap.add_argument("--list", dest="list_all", action="store_true",
593
593
  help="show every tag and the skills carrying it")
@@ -7,7 +7,6 @@ qualitatively better. Session state lives in ~/.boost/state/.
7
7
  """
8
8
  from __future__ import annotations
9
9
 
10
- import argparse
11
10
  import difflib
12
11
  import fnmatch
13
12
  import json
@@ -18,6 +17,7 @@ from collections import Counter
18
17
  from pathlib import Path
19
18
  from typing import List, Optional, Tuple
20
19
 
20
+ from .. import cliparse
21
21
  from ..core import ai, catalog, frontmatter, gitutil, journal, lockfile, paths, store, util
22
22
  from ..core import output as out
23
23
  from ..errors import BoostError
@@ -109,7 +109,7 @@ def _current_branch(cwd: Optional[Path] = None) -> Optional[str]:
109
109
  # ---------------------------------------------------------------- distill
110
110
 
111
111
  def cmd_distill(argv: List[str]) -> int:
112
- ap = argparse.ArgumentParser(
112
+ ap = cliparse.parser(
113
113
  prog="boost distill",
114
114
  description="Merge multiple skills into one deduplicated skill")
115
115
  ap.add_argument("names", nargs="+", metavar="NAME",
@@ -207,7 +207,7 @@ _LIST_RE = re.compile(r"^([-*+]|\d+[.)])\s+")
207
207
 
208
208
 
209
209
  def cmd_simulate(argv: List[str]) -> int:
210
- ap = argparse.ArgumentParser(
210
+ ap = cliparse.parser(
211
211
  prog="boost simulate",
212
212
  description="Preview how a skill would change Claude's behavior")
213
213
  ap.add_argument("name", metavar="NAME")
@@ -282,7 +282,7 @@ _CONV_RE = re.compile(
282
282
 
283
283
 
284
284
  def cmd_infer(argv: List[str]) -> int:
285
- ap = argparse.ArgumentParser(
285
+ ap = cliparse.parser(
286
286
  prog="boost infer",
287
287
  description="Generate a SKILL.md from your codebase patterns")
288
288
  ap.add_argument("--path", default=".", metavar="DIR",
@@ -510,7 +510,7 @@ _TRIVIAL = {"yes", "no", "ok", "okay", "continue", "go ahead", "sounds good",
510
510
 
511
511
 
512
512
  def cmd_absorb(argv: List[str]) -> int:
513
- ap = argparse.ArgumentParser(
513
+ ap = cliparse.parser(
514
514
  prog="boost absorb",
515
515
  description="Turn recurring chat-history patterns into a skill")
516
516
  ap.add_argument("--history", metavar="PATH",
@@ -645,7 +645,7 @@ def _absorb_template(name: str, patterns: List[Tuple[str, int]]) -> str:
645
645
  # ---------------------------------------------------------------- evolve
646
646
 
647
647
  def cmd_evolve(argv: List[str]) -> int:
648
- ap = argparse.ArgumentParser(
648
+ ap = cliparse.parser(
649
649
  prog="boost evolve",
650
650
  description="Iteratively improve a skill from feedback")
651
651
  ap.add_argument("name", metavar="NAME")
@@ -747,7 +747,7 @@ _CONTEXT_DEFAULT = {"enabled": False, "rules": []}
747
747
 
748
748
 
749
749
  def cmd_context(argv: List[str]) -> int:
750
- ap = argparse.ArgumentParser(
750
+ ap = cliparse.parser(
751
751
  prog="boost context", description="Branch-aware skill activation")
752
752
  sub = ap.add_subparsers(dest="action",
753
753
  metavar="status|enable|disable|map|unmap|apply")
@@ -890,7 +890,7 @@ _FOCUS_STATE = "focus.json"
890
890
 
891
891
 
892
892
  def cmd_focus(argv: List[str]) -> int:
893
- ap = argparse.ArgumentParser(
893
+ ap = cliparse.parser(
894
894
  prog="boost focus",
895
895
  description="Temporarily prioritize skills for a work session")
896
896
  ap.add_argument("skills", nargs="*", metavar="SKILL",
@@ -962,7 +962,7 @@ def cmd_focus(argv: List[str]) -> int:
962
962
  # ---------------------------------------------------------------- impact
963
963
 
964
964
  def cmd_impact(argv: List[str]) -> int:
965
- ap = argparse.ArgumentParser(
965
+ ap = cliparse.parser(
966
966
  prog="boost impact",
967
967
  description="Measure a skill's influence on code quality")
968
968
  ap.add_argument("name", nargs="?", metavar="NAME",
@@ -2,7 +2,6 @@
2
2
  reinstall, bundle, import, migrate, pin, unpin, snapshot, export."""
3
3
  from __future__ import annotations
4
4
 
5
- import argparse
6
5
  import io
7
6
  import json
8
7
  import os
@@ -15,6 +14,7 @@ from datetime import datetime, timezone
15
14
  from pathlib import Path
16
15
  from typing import Dict, List, Optional
17
16
 
17
+ from .. import cliparse
18
18
  from ..core import (agents, catalog, gitutil, journal, lockfile, paths,
19
19
  registry, store, util)
20
20
  from ..core import output as out
@@ -83,7 +83,7 @@ def _boostfile_text(skills: Dict[str, dict], via: str = "boost bundle dump") ->
83
83
  # ── install ──────────────────────────────────────────────────────────────
84
84
 
85
85
  def cmd_install(argv: List[str]) -> int:
86
- ap = argparse.ArgumentParser(prog="boost install",
86
+ ap = cliparse.parser(prog="boost install",
87
87
  description="Install a skill from a tap registry")
88
88
  ap.add_argument("names", nargs="+", metavar="NAME",
89
89
  help="skill name, optionally qualified as tap:skill")
@@ -155,7 +155,7 @@ def cmd_install(argv: List[str]) -> int:
155
155
  # ── uninstall ────────────────────────────────────────────────────────────
156
156
 
157
157
  def cmd_uninstall(argv: List[str]) -> int:
158
- ap = argparse.ArgumentParser(
158
+ ap = cliparse.parser(
159
159
  prog="boost uninstall",
160
160
  description="Remove an installed skill, rule, workflow, or config")
161
161
  ap.add_argument("names", nargs="+", metavar="NAME")
@@ -194,7 +194,7 @@ _PLAN_LABELS = [
194
194
 
195
195
 
196
196
  def cmd_sync(argv: List[str]) -> int:
197
- ap = argparse.ArgumentParser(
197
+ ap = cliparse.parser(
198
198
  prog="boost sync",
199
199
  description="Reconcile installed skills & symlinks against the lock file")
200
200
  ap.add_argument("--diff", action="store_true",
@@ -257,7 +257,7 @@ def cmd_sync(argv: List[str]) -> int:
257
257
  # ── update ───────────────────────────────────────────────────────────────
258
258
 
259
259
  def cmd_update(argv: List[str]) -> int:
260
- ap = argparse.ArgumentParser(prog="boost update",
260
+ ap = cliparse.parser(prog="boost update",
261
261
  description="Sync taps or update installed skills")
262
262
  ap.add_argument("tap", nargs="?", metavar="TAP", help="refresh only this tap")
263
263
  ap.add_argument("--taps-only", action="store_true",
@@ -317,7 +317,7 @@ def cmd_update(argv: List[str]) -> int:
317
317
  # ── reinstall ────────────────────────────────────────────────────────────
318
318
 
319
319
  def cmd_reinstall(argv: List[str]) -> int:
320
- ap = argparse.ArgumentParser(prog="boost reinstall",
320
+ ap = cliparse.parser(prog="boost reinstall",
321
321
  description="Reinstall a skill or all skills (force)")
322
322
  ap.add_argument("names", nargs="*", metavar="NAME")
323
323
  ap.add_argument("--all", action="store_true",
@@ -369,7 +369,7 @@ def cmd_reinstall(argv: List[str]) -> int:
369
369
  # ── bundle ───────────────────────────────────────────────────────────────
370
370
 
371
371
  def cmd_bundle(argv: List[str]) -> int:
372
- ap = argparse.ArgumentParser(prog="boost bundle",
372
+ ap = cliparse.parser(prog="boost bundle",
373
373
  description="Export/install skill sets via a Boostfile")
374
374
  ap.add_argument("action", choices=("dump", "install"))
375
375
  ap.add_argument("file", nargs="?", metavar="FILE",
@@ -481,7 +481,7 @@ def _bundle_install(file: Optional[str]) -> int:
481
481
  # ── import ───────────────────────────────────────────────────────────────
482
482
 
483
483
  def cmd_import(argv: List[str]) -> int:
484
- ap = argparse.ArgumentParser(
484
+ ap = cliparse.parser(
485
485
  prog="boost import",
486
486
  description="Import skills from a GitHub URL or local path")
487
487
  ap.add_argument("source", metavar="URL_OR_PATH")
@@ -552,7 +552,7 @@ def _import_root(root: Path, name: Optional[str], do_all: bool,
552
552
  # ── migrate ──────────────────────────────────────────────────────────────
553
553
 
554
554
  def cmd_migrate(argv: List[str]) -> int:
555
- ap = argparse.ArgumentParser(
555
+ ap = cliparse.parser(
556
556
  prog="boost migrate",
557
557
  description="Migrate skills between agents or from Skills CLI")
558
558
  ap.add_argument("--from", dest="src", metavar="AGENT",
@@ -625,7 +625,7 @@ def cmd_migrate(argv: List[str]) -> int:
625
625
  # ── pin / unpin ──────────────────────────────────────────────────────────
626
626
 
627
627
  def cmd_pin(argv: List[str]) -> int:
628
- ap = argparse.ArgumentParser(prog="boost pin",
628
+ ap = cliparse.parser(prog="boost pin",
629
629
  description="Pin a skill to its current version")
630
630
  ap.add_argument("name", metavar="NAME")
631
631
  args = ap.parse_args(argv)
@@ -633,7 +633,7 @@ def cmd_pin(argv: List[str]) -> int:
633
633
 
634
634
 
635
635
  def cmd_unpin(argv: List[str]) -> int:
636
- ap = argparse.ArgumentParser(prog="boost unpin",
636
+ ap = cliparse.parser(prog="boost unpin",
637
637
  description="Allow a pinned skill to update again")
638
638
  ap.add_argument("name", metavar="NAME")
639
639
  args = ap.parse_args(argv)
@@ -663,7 +663,7 @@ def _set_pin(name: str, pinned: bool) -> int:
663
663
  # ── snapshot ─────────────────────────────────────────────────────────────
664
664
 
665
665
  def cmd_snapshot(argv: List[str]) -> int:
666
- ap = argparse.ArgumentParser(prog="boost snapshot",
666
+ ap = cliparse.parser(prog="boost snapshot",
667
667
  description="Save & restore whole skill environments")
668
668
  ap.add_argument("action", choices=("save", "list", "restore"))
669
669
  ap.add_argument("arg", nargs="?", metavar="LABEL|ID",
@@ -784,7 +784,7 @@ def _snapshot_restore(snap_id: str) -> int:
784
784
  # ── export ───────────────────────────────────────────────────────────────
785
785
 
786
786
  def cmd_export(argv: List[str]) -> int:
787
- ap = argparse.ArgumentParser(
787
+ ap = cliparse.parser(
788
788
  prog="boost export",
789
789
  description="Package skills as shareable zip/tar archives")
790
790
  ap.add_argument("names", nargs="*", metavar="NAME",