muapi-cli 0.2.6__tar.gz → 0.2.7__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 (61) hide show
  1. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/.github/workflows/release.yml +2 -0
  2. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/PKG-INFO +1 -1
  3. muapi_cli-0.2.7/muapi/__init__.py +1 -0
  4. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/auth.py +181 -16
  5. muapi_cli-0.2.7/muapi/commands/init_cmd.py +62 -0
  6. muapi_cli-0.2.7/muapi/commands/open_cmd.py +47 -0
  7. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/config.py +17 -0
  8. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/main.py +13 -1
  9. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/npm/package.json +1 -1
  10. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/pyproject.toml +1 -1
  11. muapi_cli-0.2.6/muapi/__init__.py +0 -1
  12. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/.github/workflows/publish-langchain.yml +0 -0
  13. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/.github/workflows/publish-npm.yml +0 -0
  14. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/.github/workflows/publish-pypi.yml +0 -0
  15. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/.gitignore +0 -0
  16. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/README.md +0 -0
  17. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/cli_entry.py +0 -0
  18. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/README.md +0 -0
  19. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/docs/providers-muapi.mdx +0 -0
  20. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/AGENTS.md +0 -0
  21. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/README.md +0 -0
  22. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/creative_agent.py +0 -0
  23. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/pyproject.toml +0 -0
  24. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/skills/generate-asset/SKILL.md +0 -0
  25. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/skills/run-skill/SKILL.md +0 -0
  26. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/creative-agent/subagents.yaml +0 -0
  27. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/examples/deep_agents_demo.py +0 -0
  28. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/__init__.py +0 -0
  29. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/_client.py +0 -0
  30. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/_registry.py +0 -0
  31. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/callbacks.py +0 -0
  32. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/data/models.json +0 -0
  33. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/data/skills.json +0 -0
  34. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/loader.py +0 -0
  35. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/muapi_langchain/tools.py +0 -0
  36. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/pyproject.toml +0 -0
  37. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/integrations/langchain/scripts/refresh_registry.py +0 -0
  38. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/client.py +0 -0
  39. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/__init__.py +0 -0
  40. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/account.py +0 -0
  41. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/audio.py +0 -0
  42. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/config_cmd.py +0 -0
  43. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/docs.py +0 -0
  44. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/edit.py +0 -0
  45. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/enhance.py +0 -0
  46. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/image.py +0 -0
  47. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/keys.py +0 -0
  48. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/mcp_server.py +0 -0
  49. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/models.py +0 -0
  50. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/predict.py +0 -0
  51. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/run.py +0 -0
  52. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/upload.py +0 -0
  53. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/video.py +0 -0
  54. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/commands/workflow.py +0 -0
  55. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/dynamic_help.py +0 -0
  56. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/exitcodes.py +0 -0
  57. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/schema_introspect.py +0 -0
  58. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/muapi/utils.py +0 -0
  59. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/npm/README.md +0 -0
  60. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/npm/bin/muapi +0 -0
  61. {muapi_cli-0.2.6 → muapi_cli-0.2.7}/npm/scripts/install.js +0 -0
@@ -153,6 +153,8 @@ jobs:
153
153
  name: Publish to PyPI
154
154
  needs: build
155
155
  runs-on: ubuntu-latest
156
+ permissions:
157
+ id-token: write
156
158
  steps:
157
159
  - uses: actions/checkout@v4
158
160
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: muapi-cli
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Official CLI for muapi.ai — generative media at your fingertips
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -0,0 +1 @@
1
+ __version__ = "0.2.7"
@@ -1,16 +1,121 @@
1
1
  """muapi auth — configure API key and inspect identity."""
2
- import typer
2
+ import os
3
+ import re
4
+ import subprocess
5
+ import sys
6
+ import webbrowser
7
+
3
8
  import httpx
4
- from rich.prompt import Prompt
9
+ import typer
10
+ from rich.prompt import Confirm, Prompt
5
11
 
6
- from ..config import delete_api_key, get_api_key, save_api_key, BASE_URL
12
+ from ..config import BASE_URL, _CONFIG_FILE, delete_api_key, get_api_key, get_key_info, save_api_key
7
13
  from .. import exitcodes
8
14
  from ..utils import console, error_exit, out
9
15
 
10
16
  app = typer.Typer(help="Manage authentication and API key.")
11
17
 
12
- # Auth endpoints live at the root host, not under /api/v1
13
18
  _AUTH_BASE = BASE_URL.replace("/api/v1", "")
19
+ _ACCESS_KEYS_URL = "https://muapi.ai/access-keys"
20
+
21
+ LINKS = {
22
+ "dashboard": "https://muapi.ai/dashboard",
23
+ "access-keys": _ACCESS_KEYS_URL,
24
+ "models": "https://muapi.ai/models",
25
+ "docs": "https://muapi.ai/docs",
26
+ "pricing": "https://muapi.ai/pricing",
27
+ }
28
+
29
+
30
+ def _mask(key: str) -> str:
31
+ if len(key) < 12:
32
+ return "••••"
33
+ return key[:8] + "…" + key[-4:]
34
+
35
+
36
+ def _looks_like_key(s: str) -> bool:
37
+ s = s.strip()
38
+ return bool(re.match(r'^[A-Za-z0-9_\-]{20,}$', s) and '\n' not in s)
39
+
40
+
41
+ def _read_clipboard() -> str | None:
42
+ try:
43
+ if sys.platform == "darwin":
44
+ r = subprocess.run(["pbpaste"], capture_output=True, text=True, timeout=2)
45
+ return r.stdout.strip() or None
46
+ if sys.platform.startswith("linux"):
47
+ for cmd in (["xclip", "-o"], ["xsel", "--clipboard", "--output"]):
48
+ try:
49
+ r = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
50
+ if r.returncode == 0:
51
+ return r.stdout.strip() or None
52
+ except FileNotFoundError:
53
+ continue
54
+ if sys.platform == "win32":
55
+ r = subprocess.run(
56
+ ["powershell", "-command", "Get-Clipboard"],
57
+ capture_output=True, text=True, timeout=2,
58
+ )
59
+ return r.stdout.strip() or None
60
+ except Exception:
61
+ pass
62
+ return None
63
+
64
+
65
+ def _validate_key(api_key: str) -> tuple[bool, str]:
66
+ """Validate key against the live API. Returns (ok, error_msg)."""
67
+ try:
68
+ resp = httpx.get(
69
+ f"{BASE_URL}/account/balance",
70
+ headers={"x-api-key": api_key},
71
+ timeout=15.0,
72
+ )
73
+ if resp.status_code in (401, 403):
74
+ return False, "API rejected the key (401/403)."
75
+ if resp.status_code >= 400:
76
+ return False, f"API returned {resp.status_code}."
77
+ return True, ""
78
+ except httpx.RequestError as e:
79
+ return False, f"Could not reach {BASE_URL}: {e}"
80
+
81
+
82
+ def _find_project_config() -> str | None:
83
+ """Walk up from CWD looking for muapi.json."""
84
+ from pathlib import Path
85
+ d = Path.cwd()
86
+ while True:
87
+ candidate = d / "muapi.json"
88
+ if candidate.exists():
89
+ return str(candidate)
90
+ parent = d.parent
91
+ if parent == d:
92
+ return None
93
+ d = parent
94
+
95
+
96
+ def _do_save(api_key: str) -> None:
97
+ with console.status("[dim]Validating with api.muapi.ai…[/dim]"):
98
+ ok, reason = _validate_key(api_key)
99
+
100
+ if not ok:
101
+ console.print(f"[bold red]✖[/bold red] {reason}")
102
+ console.print()
103
+ console.print(f"[dim] Double-check at [/dim][cyan]{_ACCESS_KEYS_URL}[/cyan]")
104
+ console.print("[dim] Or set [/dim][cyan]MUAPI_API_KEY[/cyan][dim] in your shell and skip this step.[/dim]\n")
105
+ raise typer.Exit(exitcodes.AUTH_ERROR)
106
+
107
+ location = save_api_key(api_key)
108
+ location_display = "OS keychain" if location == "keychain" else str(_CONFIG_FILE)
109
+ console.print("[bold green]✔[/bold green] Signed in.")
110
+ console.print()
111
+ console.print(f" [dim]Key: [/dim][green]{_mask(api_key)}[/green]")
112
+ console.print(f" [dim]Stored: [/dim][cyan]{location_display}[/cyan]")
113
+ console.print()
114
+ console.print("[bold]Try it:[/bold]")
115
+ console.print(" [cyan]muapi account balance[/cyan]")
116
+ console.print(" [cyan]muapi image generate -p \"a cyberpunk skyline at golden hour\"[/cyan]")
117
+ console.print(" [cyan]muapi video generate -p \"drone shot over snowy peaks\" --model kling-master[/cyan]")
118
+ console.print()
14
119
 
15
120
 
16
121
  @app.command("login")
@@ -165,25 +270,85 @@ def reset_password(
165
270
 
166
271
  @app.command("configure")
167
272
  def configure(
168
- api_key: str = typer.Option(None, "--api-key", "-k", help="API key (will prompt if omitted)"),
273
+ api_key: str = typer.Option(None, "--api-key", "-k", help="API key (skips all prompts)"),
274
+ no_browser: bool = typer.Option(False, "--no-browser", help="Skip opening the access-keys page"),
169
275
  ):
170
- """Save your muapi API key to the OS keychain (or config file)."""
276
+ """Save your muapi API key opens browser, detects clipboard, validates before saving."""
277
+ if api_key:
278
+ _do_save(api_key.strip())
279
+ return
280
+
281
+ console.print()
282
+ console.print("[bold magenta] Welcome to muapi.[/bold magenta]")
283
+ console.print("[dim] Sign in once and you're set on this machine.[/dim]\n")
284
+
285
+ if not no_browser:
286
+ console.print(f"[bold] 1.[/bold] Opening [cyan]{_ACCESS_KEYS_URL}[/cyan]")
287
+ try:
288
+ webbrowser.open(_ACCESS_KEYS_URL)
289
+ except Exception:
290
+ console.print("[dim] (browser launch failed — open the link manually)[/dim]")
291
+ console.print("[bold] 2.[/bold] Copy your API key")
292
+ console.print("[bold] 3.[/bold] Paste below — we'll validate it automatically\n")
293
+
294
+ # Clipboard detection
295
+ detected: str | None = None
296
+ clip = _read_clipboard()
297
+ if clip and _looks_like_key(clip):
298
+ detected = clip
299
+
300
+ if detected:
301
+ use_it = Confirm.ask(
302
+ f" Detected a key on your clipboard ({_mask(detected)}). Use it?",
303
+ default=True,
304
+ console=console,
305
+ )
306
+ if use_it:
307
+ api_key = detected
308
+
171
309
  if not api_key:
172
- api_key = Prompt.ask("[bold]Enter your muapi API key[/bold]", password=True, console=console)
310
+ api_key = Prompt.ask("[bold] Paste your API key[/bold]", password=True, console=console)
311
+ api_key = api_key.strip()
312
+
173
313
  if not api_key:
174
- error_exit("No API key provided.")
175
- location = save_api_key(api_key.strip())
176
- console.print(f"[green]API key saved to {location}.[/green]")
314
+ error_exit("No API key provided.", exitcodes.AUTH_ERROR)
315
+
316
+ _do_save(api_key)
317
+
318
+
319
+ @app.command("status")
320
+ def status():
321
+ """Show the active API key, config location, base URL, and quick links."""
322
+ key, source = get_key_info()
323
+
324
+ console.print()
325
+ console.print("[bold]muapi CLI status[/bold]")
326
+ if key:
327
+ console.print(f" [dim]API key: [/dim][green]{_mask(key)}[/green]")
328
+ else:
329
+ console.print(f" [dim]API key: [/dim][red]not set — run [bold]muapi auth configure[/bold][/red]")
330
+ console.print(f" [dim]Source: [/dim][cyan]{source}[/cyan]")
331
+ console.print(f" [dim]Base URL: [/dim][cyan]{BASE_URL}[/cyan]")
332
+ console.print(f" [dim]Config: [/dim][cyan]{_CONFIG_FILE}[/cyan]")
333
+
334
+ project_file = _find_project_config()
335
+ if project_file:
336
+ console.print(f" [dim]Project: [/dim][cyan]{project_file}[/cyan] [dim](muapi.json detected)[/dim]")
337
+
338
+ console.print()
339
+ console.print("[bold]Useful links[/bold]")
340
+ width = max(len(k) for k in LINKS)
341
+ for name, url in LINKS.items():
342
+ console.print(f" [dim]{name.ljust(width)}[/dim] [cyan]{url}[/cyan]")
343
+ console.print()
344
+ console.print("[dim]Jump in your browser: [/dim][cyan]muapi open <target>[/cyan]")
345
+ console.print()
177
346
 
178
347
 
179
348
  @app.command("whoami")
180
349
  def whoami():
181
- """Show the currently configured API key (masked)."""
182
- key = get_api_key()
183
- if not key:
184
- error_exit("No API key configured. Run: muapi auth configure", exitcodes.AUTH_ERROR)
185
- masked = key[:8] + "..." + key[-4:]
186
- out.print(f"API key: [bold]{masked}[/bold]")
350
+ """Alias for [bold]muapi auth status[/bold]."""
351
+ status()
187
352
 
188
353
 
189
354
  @app.command("logout")
@@ -0,0 +1,62 @@
1
+ """muapi init — create a muapi.json project config in the current directory."""
2
+ import json
3
+ from pathlib import Path
4
+
5
+ import typer
6
+
7
+ from ..utils import console, error_exit
8
+
9
+ _PROJECT_FILE = "muapi.json"
10
+ _SCHEMA_URL = "https://muapi.ai/schema/cli.json"
11
+
12
+ _DEFAULT_CONFIG = {
13
+ "$schema": _SCHEMA_URL,
14
+ "defaultModel": "flux-dev-image",
15
+ "outputDir": "muapi-output",
16
+ "aliases": {},
17
+ }
18
+
19
+
20
+ def init(
21
+ yes: bool = typer.Option(False, "-y", "--yes", help="Skip prompts and write defaults"),
22
+ force: bool = typer.Option(False, "-f", "--force", help="Overwrite an existing muapi.json"),
23
+ ):
24
+ """Create a muapi.json project config with a defaultModel and alias stubs.
25
+
26
+ \b
27
+ Examples:
28
+ muapi init # interactive
29
+ muapi init -y # write defaults silently
30
+ muapi init -y -f # overwrite existing
31
+ """
32
+ target = Path.cwd() / _PROJECT_FILE
33
+
34
+ if target.exists() and not force:
35
+ error_exit(
36
+ f"{_PROJECT_FILE} already exists. Use --force to overwrite.",
37
+ )
38
+
39
+ config = dict(_DEFAULT_CONFIG)
40
+
41
+ if not yes:
42
+ from rich.prompt import Prompt
43
+ default_model = Prompt.ask(
44
+ "Default model",
45
+ default=config["defaultModel"],
46
+ console=console,
47
+ )
48
+ output_dir = Prompt.ask(
49
+ "Output directory",
50
+ default=config["outputDir"],
51
+ console=console,
52
+ )
53
+ config["defaultModel"] = default_model
54
+ config["outputDir"] = output_dir
55
+
56
+ target.write_text(json.dumps(config, indent=2) + "\n")
57
+ console.print(f"[green]Wrote {_PROJECT_FILE}[/green]")
58
+ console.print()
59
+ console.print("Now try:")
60
+ console.print(f" [cyan]muapi run -p \"a serene mountain lake at sunrise\"[/cyan]")
61
+ console.print(f" Add aliases by editing [bold]{_PROJECT_FILE}[/bold]")
62
+ console.print()
@@ -0,0 +1,47 @@
1
+ """muapi open — open muapi.ai pages in your browser."""
2
+ import webbrowser
3
+ from typing import Optional
4
+
5
+ import typer
6
+
7
+ from ..utils import console, error_exit
8
+
9
+ _TARGETS: dict[str, str] = {
10
+ "dashboard": "https://muapi.ai/dashboard",
11
+ "access-keys": "https://muapi.ai/access-keys",
12
+ "models": "https://muapi.ai/models",
13
+ "docs": "https://muapi.ai/docs",
14
+ "pricing": "https://muapi.ai/pricing",
15
+ "api": "https://api.muapi.ai/docs",
16
+ "discord": "https://discord.gg/muapi",
17
+ }
18
+
19
+
20
+ def open_page(
21
+ target: Optional[str] = typer.Argument(
22
+ None,
23
+ help="Page to open: " + ", ".join(_TARGETS.keys()),
24
+ ),
25
+ ):
26
+ """Open a muapi.ai page in your browser.
27
+
28
+ \b
29
+ Examples:
30
+ muapi open # opens dashboard
31
+ muapi open access-keys # key management
32
+ muapi open models # model catalog
33
+ muapi open docs # API docs
34
+ """
35
+ if not target:
36
+ target = "dashboard"
37
+
38
+ url = _TARGETS.get(target.lower())
39
+ if not url:
40
+ valid = ", ".join(_TARGETS.keys())
41
+ error_exit(f"Unknown target '{target}'. Valid: {valid}")
42
+
43
+ console.print(f"Opening [cyan]{url}[/cyan]")
44
+ try:
45
+ webbrowser.open(url)
46
+ except Exception as e:
47
+ error_exit(f"Could not open browser: {e}")
@@ -96,6 +96,23 @@ def get_all_settings() -> dict:
96
96
  return {}
97
97
 
98
98
 
99
+ def get_key_info() -> tuple[Optional[str], str]:
100
+ """Return (api_key, source_description) for display in status/whoami."""
101
+ if key := os.environ.get("MUAPI_API_KEY"):
102
+ return key, "env:MUAPI_API_KEY"
103
+ ok, val = _try_keyring()
104
+ if ok and val:
105
+ return val, "keychain"
106
+ if _CONFIG_FILE.exists():
107
+ try:
108
+ data = json.loads(_CONFIG_FILE.read_text())
109
+ if key := data.get("api_key"):
110
+ return key, f"file:{_CONFIG_FILE}"
111
+ except Exception:
112
+ pass
113
+ return None, "not set"
114
+
115
+
99
116
  def delete_api_key() -> None:
100
117
  ok, _ = _try_keyring()
101
118
  if ok:
@@ -5,7 +5,7 @@ import typer
5
5
  from rich import print as rprint
6
6
 
7
7
  from . import __version__
8
- from .commands import auth, account, audio, config_cmd, docs, edit, enhance, image, keys, models, predict, run, upload, video, workflow
8
+ from .commands import auth, account, audio, config_cmd, docs, edit, enhance, image, init_cmd, keys, models, open_cmd, predict, run, upload, video, workflow
9
9
  from .commands import mcp_server
10
10
  from .dynamic_help import maybe_handle_run_help
11
11
 
@@ -44,6 +44,18 @@ app.add_typer(config_cmd.app, name="config", help="Get and set persistent CLI
44
44
  app.add_typer(docs.app, name="docs", help="Access the muapi.ai API documentation.")
45
45
  app.add_typer(mcp_server.app, name="mcp", help="Run as an MCP server for AI agent integration.")
46
46
 
47
+ app.command(
48
+ "init",
49
+ help="Create a muapi.json project config with defaultModel and alias stubs.",
50
+ context_settings={"help_option_names": ["-h", "--help"]},
51
+ )(init_cmd.init)
52
+
53
+ app.command(
54
+ "open",
55
+ help="Open a muapi.ai page in your browser (dashboard, models, docs, access-keys…).",
56
+ context_settings={"help_option_names": ["-h", "--help"]},
57
+ )(open_cmd.open_page)
58
+
47
59
 
48
60
  @app.command("version")
49
61
  def version(
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muapi-cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Official CLI for muapi.ai \u2014 generate images, videos, and audio from your terminal",
5
5
  "keywords": [
6
6
  "muapi",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "muapi-cli"
7
- version = "0.2.6"
7
+ version = "0.2.7"
8
8
  description = "Official CLI for muapi.ai — generative media at your fingertips"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1 +0,0 @@
1
- __version__ = "0.2.6"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes