bingo-light 2.1.1 → 2.1.2
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.
- package/README.en.md +14 -7
- package/README.md +192 -126
- package/bingo-light +116 -0
- package/bingo_core/__init__.py +1 -1
- package/bingo_core/dep.py +652 -0
- package/bingo_core/dep_npm.py +113 -0
- package/bingo_core/dep_pip.py +178 -0
- package/bingo_core/setup.py +73 -17
- package/completions/bingo-light.bash +14 -1
- package/completions/bingo-light.fish +25 -1
- package/completions/bingo-light.zsh +20 -0
- package/mcp-server.py +106 -1
- package/package.json +1 -1
package/bingo-light
CHANGED
|
@@ -517,6 +517,72 @@ def _format_setup(result: dict) -> str:
|
|
|
517
517
|
return ""
|
|
518
518
|
|
|
519
519
|
|
|
520
|
+
def _format_dep(result: dict) -> str:
|
|
521
|
+
"""Format dep subcommand results."""
|
|
522
|
+
if result.get("ok") is False:
|
|
523
|
+
return f"{_c(RED, 'x')} {result.get('error', 'Failed')}"
|
|
524
|
+
|
|
525
|
+
lines = []
|
|
526
|
+
|
|
527
|
+
# dep patch result
|
|
528
|
+
if "patch" in result and "package" in result:
|
|
529
|
+
lines.append(f"{_c(GREEN, '✓')} {result['package']}@{result.get('version', '?')} "
|
|
530
|
+
f"→ {result['patch']} ({result.get('files_changed', 0)} file(s))")
|
|
531
|
+
return "\n".join(lines)
|
|
532
|
+
|
|
533
|
+
# dep status
|
|
534
|
+
if "packages" in result and "total_patches" in result:
|
|
535
|
+
pkgs = result["packages"]
|
|
536
|
+
if not pkgs:
|
|
537
|
+
return f"{_c(DIM, '⊘')} No dependency patches tracked"
|
|
538
|
+
lines.append(f" {_c(BOLD, 'Dependency Patches:')}")
|
|
539
|
+
lines.append("")
|
|
540
|
+
for p in pkgs:
|
|
541
|
+
status_color = GREEN if p["status"] == "ok" else YELLOW
|
|
542
|
+
icon = "✓" if p["status"] == "ok" else "!" if p["status"] == "version_mismatch" else "?"
|
|
543
|
+
lines.append(f" {_c(status_color, icon)} {p['package']} "
|
|
544
|
+
f"{_c(DIM, p['manager'])} "
|
|
545
|
+
f"{p['patched_version']}"
|
|
546
|
+
f"{' → ' + p['installed_version'] if p['status'] == 'version_mismatch' else ''} "
|
|
547
|
+
f"({p['patches']} patch(es))")
|
|
548
|
+
lines.append("")
|
|
549
|
+
return "\n".join(lines)
|
|
550
|
+
|
|
551
|
+
# dep list
|
|
552
|
+
if "patches" in result and isinstance(result["patches"], list):
|
|
553
|
+
patches = result["patches"]
|
|
554
|
+
if not patches:
|
|
555
|
+
return f"{_c(DIM, '⊘')} No patches"
|
|
556
|
+
for p in patches:
|
|
557
|
+
icon = _c(GREEN, "✓") if p.get("exists", True) else _c(RED, "✗")
|
|
558
|
+
desc = f" {_c(DIM, p['description'])}" if p.get("description") else ""
|
|
559
|
+
lines.append(f" {icon} {p['package']}/{p['patch']} {_c(DIM, 'v' + p.get('version', '?'))}{desc}")
|
|
560
|
+
return "\n".join(lines)
|
|
561
|
+
|
|
562
|
+
# dep apply / dep sync
|
|
563
|
+
if "applied" in result or "results" in result:
|
|
564
|
+
applied = result.get("applied", 0)
|
|
565
|
+
failed = result.get("failed", 0)
|
|
566
|
+
if isinstance(applied, int):
|
|
567
|
+
lines.append(f"{_c(GREEN, '✓')} {applied} applied, {failed} failed")
|
|
568
|
+
# Show sync conflicts
|
|
569
|
+
for r in result.get("results", []):
|
|
570
|
+
pkg = r.get("package", "?")
|
|
571
|
+
status = r.get("status", "?")
|
|
572
|
+
if status == "conflict":
|
|
573
|
+
for c in r.get("conflicts", []):
|
|
574
|
+
lines.append(f" {_c(YELLOW, '!')} {pkg}/{c['patch']}: {c.get('error', '?')}")
|
|
575
|
+
if c.get("hint"):
|
|
576
|
+
lines.append(f" {_c(DIM, c['hint'])}")
|
|
577
|
+
return "\n".join(lines)
|
|
578
|
+
|
|
579
|
+
# dep drop
|
|
580
|
+
if "dropped" in result:
|
|
581
|
+
return f"{_c(GREEN, '✓')} Dropped {result.get('package', '?')}/{result['dropped']}"
|
|
582
|
+
|
|
583
|
+
return f"{_c(GREEN, '✓')} Done"
|
|
584
|
+
|
|
585
|
+
|
|
520
586
|
def _format_generic(result: dict) -> str:
|
|
521
587
|
"""Fallback formatter: show message or OK."""
|
|
522
588
|
if result.get("ok") is False:
|
|
@@ -582,6 +648,14 @@ def show_help() -> str:
|
|
|
582
648
|
{cy}config{r} get|set|list Manage configuration
|
|
583
649
|
{cy}test{r} Run configured test suite
|
|
584
650
|
|
|
651
|
+
{b}Dependency Patching:{r}
|
|
652
|
+
{cy}dep patch{r} <package> [name] Patch a modified npm/pip dependency
|
|
653
|
+
{cy}dep apply{r} [package] Re-apply patches after install
|
|
654
|
+
{cy}dep sync{r} Re-apply patches after update, detect conflicts
|
|
655
|
+
{cy}dep status{r} Show patch health for all dependencies
|
|
656
|
+
{cy}dep list{r} List all dependency patches
|
|
657
|
+
{cy}dep drop{r} <package> [patch] Remove a dependency patch
|
|
658
|
+
|
|
585
659
|
{b}Automation:{r}
|
|
586
660
|
{cy}auto-sync{r} Generate GitHub Actions workflow
|
|
587
661
|
|
|
@@ -758,6 +832,27 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
758
832
|
p_setup = sub.add_parser("setup", add_help=False)
|
|
759
833
|
p_setup.add_argument("--no-completions", dest="no_completions", action="store_true")
|
|
760
834
|
|
|
835
|
+
# dep (dependency patching)
|
|
836
|
+
p_dep = sub.add_parser("dep", add_help=False)
|
|
837
|
+
dep_sub = p_dep.add_subparsers(dest="dep_command")
|
|
838
|
+
|
|
839
|
+
dp_patch = dep_sub.add_parser("patch", add_help=False)
|
|
840
|
+
dp_patch.add_argument("dep_package")
|
|
841
|
+
dp_patch.add_argument("dep_patch_name", nargs="?", default="")
|
|
842
|
+
|
|
843
|
+
dp_apply = dep_sub.add_parser("apply", add_help=False)
|
|
844
|
+
dp_apply.add_argument("dep_package", nargs="?", default="")
|
|
845
|
+
|
|
846
|
+
dep_sub.add_parser("list", add_help=False)
|
|
847
|
+
|
|
848
|
+
dep_sub.add_parser("status", add_help=False)
|
|
849
|
+
|
|
850
|
+
dep_sub.add_parser("sync", add_help=False)
|
|
851
|
+
|
|
852
|
+
dp_drop = dep_sub.add_parser("drop", add_help=False)
|
|
853
|
+
dp_drop.add_argument("dep_package")
|
|
854
|
+
dp_drop.add_argument("dep_patch_name", nargs="?", default="")
|
|
855
|
+
|
|
761
856
|
# help
|
|
762
857
|
sub.add_parser("help", add_help=False)
|
|
763
858
|
|
|
@@ -771,6 +866,26 @@ def dispatch(args: argparse.Namespace, json_mode: bool) -> Optional[dict]:
|
|
|
771
866
|
"""Dispatch a parsed command to the Repo method and return the result dict."""
|
|
772
867
|
cmd = args.command
|
|
773
868
|
|
|
869
|
+
# dep doesn't need a Repo (works with package managers, not git)
|
|
870
|
+
if cmd == "dep":
|
|
871
|
+
from bingo_core.dep import DepManager
|
|
872
|
+
dm = DepManager()
|
|
873
|
+
dcmd = getattr(args, "dep_command", "")
|
|
874
|
+
if dcmd == "patch":
|
|
875
|
+
desc = os.environ.get("BINGO_DESCRIPTION", "")
|
|
876
|
+
return dm.patch(args.dep_package, args.dep_patch_name, desc)
|
|
877
|
+
if dcmd == "apply":
|
|
878
|
+
return dm.apply(getattr(args, "dep_package", "") or "")
|
|
879
|
+
if dcmd == "list":
|
|
880
|
+
return dm.list_patches()
|
|
881
|
+
if dcmd == "status":
|
|
882
|
+
return dm.status()
|
|
883
|
+
if dcmd == "sync":
|
|
884
|
+
return dm.sync()
|
|
885
|
+
if dcmd == "drop":
|
|
886
|
+
return dm.drop(args.dep_package, getattr(args, "dep_patch_name", ""))
|
|
887
|
+
return {"ok": False, "error": f"Unknown dep subcommand: {dcmd}"}
|
|
888
|
+
|
|
774
889
|
# setup doesn't need a Repo (works outside git repos)
|
|
775
890
|
if cmd == "setup":
|
|
776
891
|
return run_setup(
|
|
@@ -959,6 +1074,7 @@ _FORMATTERS: Dict[str, Any] = {
|
|
|
959
1074
|
"undo": _format_undo,
|
|
960
1075
|
"smart-sync": _format_smart_sync,
|
|
961
1076
|
"setup": _format_setup,
|
|
1077
|
+
"dep": _format_dep,
|
|
962
1078
|
}
|
|
963
1079
|
|
|
964
1080
|
|