mirror of
https://fastgit.cc/github.com/HKUDS/CLI-Anything
synced 2026-04-20 21:00:28 +08:00
update cli-hub; more public CLIs
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""cli-hub — Download, manage, and browse CLI-Anything harnesses."""
|
||||
|
||||
__version__ = "0.2.0"
|
||||
__version__ = "0.2.1"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""cli-hub — CLI entry point."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import click
|
||||
|
||||
from cli_hub import __version__
|
||||
@@ -43,6 +46,7 @@ def install(name):
|
||||
click.secho(f"✓ {msg}", fg="green")
|
||||
if cli:
|
||||
click.echo(f" Run it with: {cli['entry_point']}")
|
||||
click.echo(f" Or launch: cli-hub launch {cli['name']}")
|
||||
if cli.get("_source") == "public" and cli.get("npx_cmd"):
|
||||
click.echo(f" Or use npx: {cli['npx_cmd']}")
|
||||
else:
|
||||
@@ -201,5 +205,27 @@ def info(name):
|
||||
click.echo()
|
||||
|
||||
|
||||
@main.command()
|
||||
@click.argument("name")
|
||||
@click.argument("args", nargs=-1)
|
||||
def launch(name, args):
|
||||
"""Launch an installed CLI, passing through any extra arguments."""
|
||||
cli = get_cli(name)
|
||||
if not cli:
|
||||
click.secho(f"CLI '{name}' not found in registry.", fg="red", err=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
entry = cli["entry_point"]
|
||||
if not shutil.which(entry):
|
||||
click.secho(
|
||||
f"'{entry}' not found on PATH. Install it first: cli-hub install {name}",
|
||||
fg="red",
|
||||
err=True,
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
os.execvp(entry, [entry] + list(args))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -31,13 +31,38 @@ def _find_npm():
|
||||
return shutil.which("npm")
|
||||
|
||||
|
||||
def _find_uv():
|
||||
"""Find uv executable. Returns path or None."""
|
||||
return shutil.which("uv")
|
||||
|
||||
|
||||
_UV_INSTALL_HINT = (
|
||||
"uv is not installed. Install it first:\n"
|
||||
" macOS / Linux: curl -LsSf https://astral.sh/uv/install.sh | sh\n"
|
||||
" Windows: powershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"\n"
|
||||
" pip: pip install uv\n"
|
||||
" brew: brew install uv\n"
|
||||
" See also: https://docs.astral.sh/uv/getting-started/installation/"
|
||||
)
|
||||
|
||||
|
||||
_SHELL_METACHARACTERS = ("|", "&&", "||", ";", "$(", "`")
|
||||
|
||||
|
||||
def _run_command(cmd):
|
||||
"""Run a command string without invoking a shell."""
|
||||
"""Run a command string.
|
||||
|
||||
Uses shell=True when the command contains shell operators (pipes, &&, etc.)
|
||||
so that script-type installs like ``curl … | bash`` work correctly.
|
||||
Commands come from the trusted registry, not from user input.
|
||||
"""
|
||||
use_shell = any(c in cmd for c in _SHELL_METACHARACTERS)
|
||||
try:
|
||||
return subprocess.run(
|
||||
shlex.split(cmd),
|
||||
cmd if use_shell else shlex.split(cmd),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
shell=use_shell,
|
||||
)
|
||||
except FileNotFoundError as exc:
|
||||
missing = exc.filename or shlex.split(cmd)[0]
|
||||
@@ -69,6 +94,8 @@ def _install_strategy(cli):
|
||||
return "pip"
|
||||
if cli.get("npm_package") or cli.get("package_manager") == "npm":
|
||||
return "npm"
|
||||
if cli.get("package_manager") == "uv":
|
||||
return "uv"
|
||||
if cli.get("package_manager") == "bundled":
|
||||
return "bundled"
|
||||
return "command"
|
||||
@@ -170,6 +197,42 @@ def _pip_update(cli):
|
||||
return False, f"Update failed:\n{result.stderr}"
|
||||
|
||||
|
||||
# ── uv operations (public CLIs) ──
|
||||
|
||||
|
||||
def _uv_install(cli):
|
||||
if _find_uv() is None:
|
||||
return False, _UV_INSTALL_HINT
|
||||
result = _run_command(cli["install_cmd"])
|
||||
if result.returncode == 0:
|
||||
return True, f"Installed {cli['display_name']} ({cli['entry_point']})"
|
||||
return False, f"uv install failed:\n{result.stderr or result.stdout}"
|
||||
|
||||
|
||||
def _uv_uninstall(cli):
|
||||
if _find_uv() is None:
|
||||
return False, _UV_INSTALL_HINT
|
||||
uninstall_cmd = cli.get("uninstall_cmd")
|
||||
if not uninstall_cmd:
|
||||
return False, f"No uninstall command is defined for {cli['display_name']}."
|
||||
result = _run_command(uninstall_cmd)
|
||||
if result.returncode == 0:
|
||||
return True, f"Uninstalled {cli['display_name']}"
|
||||
return False, f"uv uninstall failed:\n{result.stderr or result.stdout}"
|
||||
|
||||
|
||||
def _uv_update(cli):
|
||||
if _find_uv() is None:
|
||||
return False, _UV_INSTALL_HINT
|
||||
update_cmd = cli.get("update_cmd")
|
||||
if not update_cmd:
|
||||
return False, f"No update command is defined for {cli['display_name']}."
|
||||
result = _run_command(update_cmd)
|
||||
if result.returncode == 0:
|
||||
return True, f"Updated {cli['display_name']}"
|
||||
return False, f"uv update failed:\n{result.stderr or result.stdout}"
|
||||
|
||||
|
||||
# ── npm operations (public CLIs) ──
|
||||
|
||||
|
||||
@@ -223,6 +286,7 @@ def _perform_action(cli, action):
|
||||
actions = {
|
||||
"pip": {"install": _pip_install, "uninstall": _pip_uninstall, "update": _pip_update},
|
||||
"npm": {"install": _npm_install, "uninstall": _npm_uninstall, "update": _npm_update},
|
||||
"uv": {"install": _uv_install, "uninstall": _uv_uninstall, "update": _uv_update},
|
||||
"command": {"install": _generic_install, "uninstall": _generic_uninstall, "update": _generic_update},
|
||||
"bundled": {"install": _bundled_install, "uninstall": _bundled_uninstall, "update": _bundled_update},
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="cli-anything-hub",
|
||||
version="0.2.0",
|
||||
version="0.2.1",
|
||||
description="Package manager for CLI-Anything — browse, install, and manage 40+ agent-native CLI interfaces for GUI applications",
|
||||
long_description=open("README.md").read(),
|
||||
long_description_content_type="text/markdown",
|
||||
|
||||
@@ -12,7 +12,16 @@ import requests
|
||||
|
||||
from cli_hub import __version__
|
||||
from cli_hub.registry import fetch_registry, fetch_all_clis, get_cli, search_clis, list_categories
|
||||
from cli_hub.installer import install_cli, uninstall_cli, get_installed, _load_installed, _save_installed
|
||||
from cli_hub.installer import (
|
||||
install_cli,
|
||||
uninstall_cli,
|
||||
get_installed,
|
||||
_load_installed,
|
||||
_save_installed,
|
||||
_run_command,
|
||||
_install_strategy,
|
||||
_UV_INSTALL_HINT,
|
||||
)
|
||||
from cli_hub.analytics import _is_enabled, track_event, track_install, track_uninstall as analytics_track_uninstall, track_visit, track_first_run, _detect_is_agent
|
||||
from cli_hub.cli import main
|
||||
|
||||
@@ -262,6 +271,221 @@ class TestInstaller:
|
||||
assert "already available" in msg
|
||||
|
||||
|
||||
GENERATE_VEO_CLI = {
|
||||
"name": "generate-veo-video",
|
||||
"display_name": "Generate Veo Video",
|
||||
"version": "0.2.5",
|
||||
"description": "CLI for generating videos with Google Veo 3.1",
|
||||
"category": "ai",
|
||||
"entry_point": "generate-veo",
|
||||
"_source": "public",
|
||||
"package_manager": "uv",
|
||||
"install_cmd": "uv tool install git+https://github.com/charles-forsyth/generate-veo-video.git",
|
||||
"uninstall_cmd": "uv tool uninstall generate-veo-video",
|
||||
"update_cmd": "uv tool upgrade generate-veo-video",
|
||||
}
|
||||
|
||||
|
||||
class TestUvStrategy:
|
||||
"""Tests for uv-managed public CLI installs (e.g. generate-veo-video)."""
|
||||
|
||||
def test_strategy_detected_as_uv(self):
|
||||
assert _install_strategy(GENERATE_VEO_CLI) == "uv"
|
||||
|
||||
def test_strategy_uv_not_overridden_by_install_strategy_field(self):
|
||||
"""If install_strategy is explicitly set it takes priority over package_manager."""
|
||||
cli = {**GENERATE_VEO_CLI, "install_strategy": "command"}
|
||||
assert _install_strategy(cli) == "command"
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
@patch("cli_hub.installer._find_uv", return_value="/usr/bin/uv")
|
||||
def test_install_uv_success(self, mock_find_uv, mock_get_cli, mock_run):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
success, msg = install_cli("generate-veo-video")
|
||||
assert success
|
||||
assert "Generate Veo Video" in msg
|
||||
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer._find_uv", return_value=None)
|
||||
def test_install_uv_missing_shows_hint(self, mock_find_uv, mock_get_cli):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
success, msg = install_cli("generate-veo-video")
|
||||
assert not success
|
||||
assert "uv is not installed" in msg
|
||||
assert "astral.sh/uv" in msg
|
||||
assert "brew install uv" in msg
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
@patch("cli_hub.installer._find_uv", return_value="/usr/bin/uv")
|
||||
def test_uninstall_uv_success(self, mock_find_uv, mock_get_cli, mock_run):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
success, msg = uninstall_cli("generate-veo-video")
|
||||
assert success
|
||||
assert "Generate Veo Video" in msg
|
||||
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer._find_uv", return_value=None)
|
||||
def test_uninstall_uv_missing_shows_hint(self, mock_find_uv, mock_get_cli):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
success, msg = uninstall_cli("generate-veo-video")
|
||||
assert not success
|
||||
assert "uv is not installed" in msg
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
@patch("cli_hub.installer._find_uv", return_value="/usr/bin/uv")
|
||||
def test_update_uv_success(self, mock_find_uv, mock_get_cli, mock_run):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
from cli_hub.installer import update_cli
|
||||
success, msg = update_cli("generate-veo-video")
|
||||
assert success
|
||||
assert "Generate Veo Video" in msg
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer._find_uv", return_value="/usr/bin/uv")
|
||||
def test_install_uv_failure_propagated(self, mock_find_uv, mock_get_cli, mock_run):
|
||||
mock_get_cli.return_value = GENERATE_VEO_CLI
|
||||
mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="error: package not found")
|
||||
success, msg = install_cli("generate-veo-video")
|
||||
assert not success
|
||||
assert "failed" in msg.lower()
|
||||
|
||||
|
||||
# ─── Script / pipe-command strategy tests (jimeng / Dreamina) ─────────
|
||||
|
||||
JIMENG_CLI = {
|
||||
"name": "jimeng",
|
||||
"display_name": "Jimeng / Dreamina CLI",
|
||||
"version": "latest",
|
||||
"description": "ByteDance AI image and video generation CLI",
|
||||
"category": "ai",
|
||||
"entry_point": "dreamina",
|
||||
"_source": "public",
|
||||
"install_strategy": "command",
|
||||
"package_manager": "script",
|
||||
"install_cmd": "curl -s https://jimeng.jianying.com/cli | bash",
|
||||
}
|
||||
|
||||
|
||||
class TestScriptStrategy:
|
||||
"""Tests for script/pipe-command installs (e.g. jimeng curl | bash)."""
|
||||
|
||||
# ── _install_strategy routing ──────────────────────────────────────
|
||||
|
||||
def test_strategy_detected_as_command(self):
|
||||
"""install_strategy field takes priority — jimeng routes to 'command'."""
|
||||
assert _install_strategy(JIMENG_CLI) == "command"
|
||||
|
||||
def test_strategy_script_package_manager_without_field_falls_back_to_command(self):
|
||||
"""Without install_strategy field, script package_manager still routes to 'command'."""
|
||||
cli = {**JIMENG_CLI}
|
||||
del cli["install_strategy"]
|
||||
assert _install_strategy(cli) == "command"
|
||||
|
||||
# ── _run_command shell detection ───────────────────────────────────
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
def test_run_command_uses_shell_true_for_pipe(self, mock_run):
|
||||
"""Pipe character triggers shell=True so bash can interpret it."""
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
_run_command("curl -s https://jimeng.jianying.com/cli | bash")
|
||||
mock_run.assert_called_once()
|
||||
_, kwargs = mock_run.call_args
|
||||
assert kwargs.get("shell") is True
|
||||
# cmd passed as a single string, not a list
|
||||
args = mock_run.call_args[0][0]
|
||||
assert isinstance(args, str)
|
||||
assert "| bash" in args
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
def test_run_command_uses_shell_false_for_simple_command(self, mock_run):
|
||||
"""Simple commands (no shell operators) must NOT use shell=True."""
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
_run_command("brew install --cask 1password-cli")
|
||||
_, kwargs = mock_run.call_args
|
||||
assert kwargs.get("shell") is False or kwargs.get("shell") is None
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
def test_run_command_uses_shell_true_for_and_operator(self, mock_run):
|
||||
"""&& operator also triggers shell=True."""
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
_run_command("curl -O https://example.com/install.sh && bash install.sh")
|
||||
_, kwargs = mock_run.call_args
|
||||
assert kwargs.get("shell") is True
|
||||
|
||||
# ── Full install flow ──────────────────────────────────────────────
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
def test_install_jimeng_success(self, mock_get_cli, mock_run):
|
||||
"""install_cli('jimeng') succeeds and invokes the pipe command via shell."""
|
||||
mock_get_cli.return_value = JIMENG_CLI
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
|
||||
success, msg = install_cli("jimeng")
|
||||
|
||||
assert success, f"Expected success but got: {msg}"
|
||||
assert "Jimeng" in msg
|
||||
|
||||
mock_run.assert_called_once()
|
||||
_, kwargs = mock_run.call_args
|
||||
assert kwargs.get("shell") is True
|
||||
assert "| bash" in mock_run.call_args[0][0]
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
def test_install_jimeng_failure_propagated(self, mock_get_cli, mock_run):
|
||||
"""A non-zero exit from the curl|bash script surfaces as failure."""
|
||||
mock_get_cli.return_value = JIMENG_CLI
|
||||
mock_run.return_value = MagicMock(
|
||||
returncode=1, stdout="", stderr="curl: (6) Could not resolve host"
|
||||
)
|
||||
|
||||
success, msg = install_cli("jimeng")
|
||||
|
||||
assert not success
|
||||
assert "failed" in msg.lower()
|
||||
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
def test_uninstall_jimeng_no_cmd_returns_graceful_message(self, mock_get_cli):
|
||||
"""Uninstalling jimeng (no uninstall_cmd defined) returns a non-crash message."""
|
||||
mock_get_cli.return_value = JIMENG_CLI # no uninstall_cmd key
|
||||
|
||||
success, msg = uninstall_cli("jimeng")
|
||||
|
||||
assert not success
|
||||
# Should mention the CLI name or explain no command available — never crash
|
||||
assert msg
|
||||
|
||||
@patch("cli_hub.installer.subprocess.run")
|
||||
@patch("cli_hub.installer.get_cli")
|
||||
@patch("cli_hub.installer.INSTALLED_FILE", Path(tempfile.mktemp()))
|
||||
def test_install_jimeng_recorded_in_installed_json(self, mock_get_cli, mock_run):
|
||||
"""After a successful install, jimeng appears in installed.json."""
|
||||
installed_file = Path(tempfile.mktemp())
|
||||
mock_get_cli.return_value = JIMENG_CLI
|
||||
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
||||
|
||||
with patch("cli_hub.installer.INSTALLED_FILE", installed_file):
|
||||
success, _ = install_cli("jimeng")
|
||||
assert success
|
||||
data = json.loads(installed_file.read_text())
|
||||
assert "jimeng" in data
|
||||
assert data["jimeng"]["strategy"] == "command"
|
||||
assert data["jimeng"]["package_manager"] == "script"
|
||||
|
||||
|
||||
# ─── Analytics tests ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -501,3 +725,48 @@ class TestCLI:
|
||||
"""When agent env detected, track_visit is called with is_agent=True."""
|
||||
result = self.runner.invoke(main, ["--version"])
|
||||
mock_visit.assert_called_once_with(is_agent=True)
|
||||
|
||||
@patch("cli_hub.cli.track_first_run")
|
||||
@patch("cli_hub.cli.track_visit")
|
||||
@patch("cli_hub.cli._detect_is_agent", return_value=False)
|
||||
@patch("cli_hub.cli.install_cli", return_value=(True, "Installed Jimeng / Dreamina CLI (dreamina)"))
|
||||
@patch("cli_hub.cli.get_cli", return_value={**SAMPLE_REGISTRY["clis"][0], "entry_point": "dreamina", "name": "jimeng", "display_name": "Jimeng / Dreamina CLI", "version": "latest", "_source": "public"})
|
||||
@patch("cli_hub.cli.track_install")
|
||||
def test_install_shows_launch_hint(self, mock_track, mock_get, mock_install, mock_detect, mock_visit, mock_first_run):
|
||||
"""Post-install output includes both entry point and cli-hub launch hint."""
|
||||
result = self.runner.invoke(main, ["install", "jimeng"])
|
||||
assert result.exit_code == 0
|
||||
assert "dreamina" in result.output
|
||||
assert "cli-hub launch jimeng" in result.output
|
||||
|
||||
@patch("cli_hub.cli.track_first_run")
|
||||
@patch("cli_hub.cli.track_visit")
|
||||
@patch("cli_hub.cli._detect_is_agent", return_value=False)
|
||||
@patch("cli_hub.cli.shutil.which", return_value="/usr/bin/dreamina")
|
||||
@patch("cli_hub.cli.os.execvp")
|
||||
@patch("cli_hub.cli.get_cli", return_value=JIMENG_CLI)
|
||||
def test_launch_execs_entry_point(self, mock_get, mock_execvp, mock_which, mock_detect, mock_visit, mock_first_run):
|
||||
"""launch execs the CLI entry point, passing through extra args."""
|
||||
result = self.runner.invoke(main, ["launch", "jimeng", "login"])
|
||||
mock_execvp.assert_called_once_with("dreamina", ["dreamina", "login"])
|
||||
|
||||
@patch("cli_hub.cli.track_first_run")
|
||||
@patch("cli_hub.cli.track_visit")
|
||||
@patch("cli_hub.cli._detect_is_agent", return_value=False)
|
||||
@patch("cli_hub.cli.shutil.which", return_value=None)
|
||||
@patch("cli_hub.cli.get_cli", return_value=JIMENG_CLI)
|
||||
def test_launch_not_on_path_shows_install_hint(self, mock_get, mock_which, mock_detect, mock_visit, mock_first_run):
|
||||
"""launch fails gracefully when entry point not on PATH."""
|
||||
result = self.runner.invoke(main, ["launch", "jimeng"])
|
||||
assert result.exit_code == 1
|
||||
assert "cli-hub install jimeng" in result.output
|
||||
|
||||
@patch("cli_hub.cli.track_first_run")
|
||||
@patch("cli_hub.cli.track_visit")
|
||||
@patch("cli_hub.cli._detect_is_agent", return_value=False)
|
||||
@patch("cli_hub.cli.get_cli", return_value=None)
|
||||
def test_launch_unknown_cli(self, mock_get, mock_detect, mock_visit, mock_first_run):
|
||||
"""launch with an unknown CLI name exits with error."""
|
||||
result = self.runner.invoke(main, ["launch", "nonexistent"])
|
||||
assert result.exit_code == 1
|
||||
assert "not found" in result.output
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"meta": {
|
||||
"repo": "https://github.com/HKUDS/CLI-Anything",
|
||||
"description": "Public CLI Registry — Third-party and official CLIs managed by CLI-Hub across npm, bundled, brew, and other install methods",
|
||||
"updated": "2026-04-15"
|
||||
"updated": "2026-04-16"
|
||||
},
|
||||
"clis": [
|
||||
{
|
||||
@@ -15,10 +15,10 @@
|
||||
"homepage": "https://github.com/larksuite/cli",
|
||||
"source_url": "https://github.com/larksuite/cli",
|
||||
"package_manager": "npm",
|
||||
"npm_package": "@anthropic-ai/feishu-cli",
|
||||
"install_cmd": "npm install -g @anthropic-ai/feishu-cli",
|
||||
"npx_cmd": "npx @anthropic-ai/feishu-cli",
|
||||
"entry_point": "feishu",
|
||||
"npm_package": "@larksuite/cli",
|
||||
"install_cmd": "npm install -g @larksuite/cli",
|
||||
"npx_cmd": "npx @larksuite/cli",
|
||||
"entry_point": "lark-cli",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "larksuite",
|
||||
@@ -174,6 +174,48 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "generate-veo-video",
|
||||
"display_name": "Generate Veo Video",
|
||||
"version": "0.2.5",
|
||||
"description": "CLI for generating videos with Google Veo 3.1 via Vertex AI/Gemini — text-to-video, image-to-video, reference images, frame morphing, and video extension",
|
||||
"category": "ai",
|
||||
"requires": "Python >= 3.10, uv, GOOGLE_CLOUD_PROJECT env var (GEMINI_API_KEY optional)",
|
||||
"homepage": "https://github.com/charles-forsyth/generate-veo-video",
|
||||
"source_url": "https://github.com/charles-forsyth/generate-veo-video",
|
||||
"package_manager": "uv",
|
||||
"install_cmd": "uv tool install git+https://github.com/charles-forsyth/generate-veo-video.git",
|
||||
"uninstall_cmd": "uv tool uninstall generate-veo-video",
|
||||
"update_cmd": "uv tool upgrade generate-veo-video",
|
||||
"entry_point": "generate-veo",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "charles-forsyth",
|
||||
"url": "https://github.com/charles-forsyth"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jimeng",
|
||||
"display_name": "Jimeng / Dreamina CLI",
|
||||
"version": "latest",
|
||||
"description": "Official ByteDance AI image and video generation CLI — text-to-image, text-to-video, image-to-video, digital human, and intelligent canvas; domestic brand is Jimeng (即梦), international brand is Dreamina",
|
||||
"category": "ai",
|
||||
"requires": "Jimeng / Dreamina account and API key",
|
||||
"homepage": "https://jimeng.jianying.com/",
|
||||
"docs_url": "https://bytedance.larkoffice.com/wiki/FVTwwm0bGiishxkKOoScdHR2nsg",
|
||||
"source_url": null,
|
||||
"package_manager": "script",
|
||||
"install_strategy": "command",
|
||||
"install_cmd": "curl -s https://jimeng.jianying.com/cli | bash",
|
||||
"entry_point": "dreamina",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "ByteDance",
|
||||
"url": "https://www.bytedance.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "obsidian-cli",
|
||||
"display_name": "Obsidian CLI",
|
||||
|
||||
Reference in New Issue
Block a user