vcursor-cli 1.0.0__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.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include vcursor *.py
4
+ recursive-include tests *.py
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: vcursor-cli
3
+ Version: 1.0.0
4
+ Summary: VCursor SDK & CLI - Generate videos from text, images, and URLs using AI
5
+ Author-email: Julius <support@vcursor.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://cli.vcursor.com
8
+ Project-URL: Repository, https://github.com/JThh/vcursor
9
+ Project-URL: Documentation, https://cli.vcursor.com/docs
10
+ Keywords: video,ai,generation,cli,vcursor,sdk
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Multimedia :: Video
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: httpx>=0.25.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
28
+
29
+ # VCursor Python SDK & CLI
30
+
31
+ Generate videos from text, images, and URLs using AI.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install vcursor
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ### As a library (embedded in code)
42
+
43
+ ```python
44
+ from vcursor import VCursor
45
+
46
+ client = VCursor(api_key="vk-...")
47
+
48
+ # Submit a video generation task
49
+ resp = client.submit("a cat playing piano in a jazz club")
50
+
51
+ # Wait for completion with progress callback
52
+ result = client.wait_for_completion(
53
+ resp.task_id,
54
+ on_progress=lambda p: print(f"{p.data.progress}%")
55
+ )
56
+
57
+ print(result.data.products.url)
58
+ ```
59
+
60
+ ### Async usage
61
+
62
+ ```python
63
+ import asyncio
64
+ from vcursor import VCursorAsync
65
+
66
+ async def main():
67
+ async with VCursorAsync(api_key="vk-...") as client:
68
+ resp = await client.submit("sunset timelapse over mountains")
69
+ result = await client.wait_for_completion(resp.task_id)
70
+ print(result.data.products.url)
71
+
72
+ asyncio.run(main())
73
+ ```
74
+
75
+ ### Concurrency limiting
76
+
77
+ The server enforces per-user rate limits based on subscription tier:
78
+
79
+ | Tier | Standard Requests | Agent Requests | Window |
80
+ |------|-------------------|----------------|-----------|
81
+ | Free | 3 | 1 | Lifetime |
82
+ | Pro | 30/hr | 5/hr | Rolling 1h|
83
+ | Plus | 120/hr | 15/hr | Rolling 1h|
84
+
85
+ ```python
86
+ # Check current rate limit status
87
+ status = client.check_concurrency("standard")
88
+ print(f"Standard: {status.summary['standard'].used}/{status.summary['standard'].limit}")
89
+ print(f"Agent: {status.summary['agent'].used}/{status.summary['agent'].limit}")
90
+
91
+ # Client-side limit (capped at server limit)
92
+ client = VCursor(api_key="vk-...", max_concurrency=10)
93
+ ```
94
+
95
+ ### As a CLI
96
+
97
+ ```bash
98
+ # Authenticate
99
+ vcursor login
100
+
101
+ # Generate a video
102
+ vcursor generate "a cat playing piano"
103
+
104
+ # Agent mode
105
+ vcursor generate --agent "create a 30s commercial"
106
+
107
+ # Check concurrency status
108
+ vcursor concurrency
109
+
110
+ # With concurrency limit
111
+ vcursor generate --max-concurrency 2 "sunset timelapse"
112
+ ```
113
+
114
+ ## API Reference
115
+
116
+ ### `VCursor` / `VCursorAsync`
117
+
118
+ | Method | Description |
119
+ |---------------------------|----------------------------------------|
120
+ | `submit(prompt, **kw)` | Submit a standard video generation task |
121
+ | `get_progress(task_id)` | Get task progress |
122
+ | `wait_for_completion()` | Poll until task completes |
123
+ | `cancel_task(task_id)` | Cancel a running task |
124
+ | `submit_agent(message)` | Submit an agent mode task |
125
+ | `get_agent_progress()` | Get agent task progress |
126
+ | `wait_for_agent_completion()` | Poll until agent task completes |
127
+ | `check_concurrency()` | Check concurrency limit status |
128
+
129
+ ## Configuration
130
+
131
+ Config is stored in `~/.vcursor/config.json` (shared with the Node.js CLI).
132
+
133
+ Environment variables:
134
+ - `VCURSOR_API_KEY` - API key
135
+ - `VCURSOR_SERVER` - Server URL
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,111 @@
1
+ # VCursor Python SDK & CLI
2
+
3
+ Generate videos from text, images, and URLs using AI.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install vcursor
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### As a library (embedded in code)
14
+
15
+ ```python
16
+ from vcursor import VCursor
17
+
18
+ client = VCursor(api_key="vk-...")
19
+
20
+ # Submit a video generation task
21
+ resp = client.submit("a cat playing piano in a jazz club")
22
+
23
+ # Wait for completion with progress callback
24
+ result = client.wait_for_completion(
25
+ resp.task_id,
26
+ on_progress=lambda p: print(f"{p.data.progress}%")
27
+ )
28
+
29
+ print(result.data.products.url)
30
+ ```
31
+
32
+ ### Async usage
33
+
34
+ ```python
35
+ import asyncio
36
+ from vcursor import VCursorAsync
37
+
38
+ async def main():
39
+ async with VCursorAsync(api_key="vk-...") as client:
40
+ resp = await client.submit("sunset timelapse over mountains")
41
+ result = await client.wait_for_completion(resp.task_id)
42
+ print(result.data.products.url)
43
+
44
+ asyncio.run(main())
45
+ ```
46
+
47
+ ### Concurrency limiting
48
+
49
+ The server enforces per-user rate limits based on subscription tier:
50
+
51
+ | Tier | Standard Requests | Agent Requests | Window |
52
+ |------|-------------------|----------------|-----------|
53
+ | Free | 3 | 1 | Lifetime |
54
+ | Pro | 30/hr | 5/hr | Rolling 1h|
55
+ | Plus | 120/hr | 15/hr | Rolling 1h|
56
+
57
+ ```python
58
+ # Check current rate limit status
59
+ status = client.check_concurrency("standard")
60
+ print(f"Standard: {status.summary['standard'].used}/{status.summary['standard'].limit}")
61
+ print(f"Agent: {status.summary['agent'].used}/{status.summary['agent'].limit}")
62
+
63
+ # Client-side limit (capped at server limit)
64
+ client = VCursor(api_key="vk-...", max_concurrency=10)
65
+ ```
66
+
67
+ ### As a CLI
68
+
69
+ ```bash
70
+ # Authenticate
71
+ vcursor login
72
+
73
+ # Generate a video
74
+ vcursor generate "a cat playing piano"
75
+
76
+ # Agent mode
77
+ vcursor generate --agent "create a 30s commercial"
78
+
79
+ # Check concurrency status
80
+ vcursor concurrency
81
+
82
+ # With concurrency limit
83
+ vcursor generate --max-concurrency 2 "sunset timelapse"
84
+ ```
85
+
86
+ ## API Reference
87
+
88
+ ### `VCursor` / `VCursorAsync`
89
+
90
+ | Method | Description |
91
+ |---------------------------|----------------------------------------|
92
+ | `submit(prompt, **kw)` | Submit a standard video generation task |
93
+ | `get_progress(task_id)` | Get task progress |
94
+ | `wait_for_completion()` | Poll until task completes |
95
+ | `cancel_task(task_id)` | Cancel a running task |
96
+ | `submit_agent(message)` | Submit an agent mode task |
97
+ | `get_agent_progress()` | Get agent task progress |
98
+ | `wait_for_agent_completion()` | Poll until agent task completes |
99
+ | `check_concurrency()` | Check concurrency limit status |
100
+
101
+ ## Configuration
102
+
103
+ Config is stored in `~/.vcursor/config.json` (shared with the Node.js CLI).
104
+
105
+ Environment variables:
106
+ - `VCURSOR_API_KEY` - API key
107
+ - `VCURSOR_SERVER` - Server URL
108
+
109
+ ## License
110
+
111
+ MIT
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vcursor-cli"
7
+ version = "1.0.0"
8
+ description = "VCursor SDK & CLI - Generate videos from text, images, and URLs using AI"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Julius", email = "support@vcursor.com"},
14
+ ]
15
+ keywords = ["video", "ai", "generation", "cli", "vcursor", "sdk"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Multimedia :: Video",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ ]
29
+ dependencies = [
30
+ "httpx>=0.25.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0",
36
+ "pytest-asyncio>=0.21",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://cli.vcursor.com"
41
+ Repository = "https://github.com/JThh/vcursor"
42
+ Documentation = "https://cli.vcursor.com/docs"
43
+
44
+ [project.scripts]
45
+ vcursor = "vcursor.cli:main"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["."]
49
+ include = ["vcursor*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,110 @@
1
+ """Basic tests for type serialization/deserialization."""
2
+
3
+ from vcursor.types import (
4
+ SubmitRequest,
5
+ SubmitResponse,
6
+ TaskProgress,
7
+ AgentSubmitRequest,
8
+ AgentProgress,
9
+ ConcurrencyStatus,
10
+ )
11
+
12
+
13
+ def test_submit_request_to_dict():
14
+ req = SubmitRequest(prompt="hello world")
15
+ d = req.to_dict()
16
+ assert d == {"prompt": "hello world"}
17
+
18
+
19
+ def test_submit_request_with_extras():
20
+ req = SubmitRequest(
21
+ prompt="test",
22
+ media_keys=["key1"],
23
+ reference_urls=["https://example.com"],
24
+ submission_mode="plan",
25
+ )
26
+ d = req.to_dict()
27
+ assert d["media_keys"] == ["key1"]
28
+ assert d["reference_urls"] == ["https://example.com"]
29
+ assert d["submission_mode"] == "plan"
30
+
31
+
32
+ def test_submit_response_from_dict():
33
+ resp = SubmitResponse.from_dict({
34
+ "code": 200,
35
+ "message": "OK",
36
+ "task_id": "abc123",
37
+ "mode": "text2video",
38
+ })
39
+ assert resp.task_id == "abc123"
40
+ assert resp.mode == "text2video"
41
+
42
+
43
+ def test_task_progress_from_dict():
44
+ progress = TaskProgress.from_dict({
45
+ "code": 200,
46
+ "message": "OK",
47
+ "data": {
48
+ "task_id": "t1",
49
+ "status": "processing",
50
+ "progress": 50.0,
51
+ "queuing_time": 1.0,
52
+ "remaining_process_time": 10.0,
53
+ "total_process_time": 20.0,
54
+ "products": {
55
+ "url": "https://cdn.example.com/video.mp4",
56
+ "upload_completed": True,
57
+ },
58
+ },
59
+ })
60
+ assert progress.data.status == "processing"
61
+ assert progress.data.progress == 50.0
62
+ assert progress.data.products.url == "https://cdn.example.com/video.mp4"
63
+
64
+
65
+ def test_agent_submit_request_to_dict():
66
+ req = AgentSubmitRequest(message="make a commercial", duration="30s")
67
+ d = req.to_dict()
68
+ assert d == {"message": "make a commercial", "duration": "30s"}
69
+
70
+
71
+ def test_agent_progress_from_dict():
72
+ p = AgentProgress.from_dict({
73
+ "task_id": "a1",
74
+ "status": "completed",
75
+ "progress": 100.0,
76
+ "video_url": "https://cdn.example.com/agent.mp4",
77
+ })
78
+ assert p.status == "completed"
79
+ assert p.video_url == "https://cdn.example.com/agent.mp4"
80
+
81
+
82
+ def test_concurrency_status_from_dict():
83
+ s = ConcurrencyStatus.from_dict({
84
+ "allowed": True,
85
+ "limit": 30,
86
+ "used": 5,
87
+ "remaining": 25,
88
+ "category": "standard",
89
+ "tier": "pro",
90
+ "bypassEnabled": False,
91
+ "windowHours": 1,
92
+ "resetAt": None,
93
+ "summary": {
94
+ "standard": {"used": 5, "limit": 30, "remaining": 25},
95
+ "agent": {"used": 1, "limit": 5, "remaining": 4},
96
+ },
97
+ })
98
+ assert s.allowed is True
99
+ assert s.limit == 30
100
+ assert s.used == 5
101
+ assert s.remaining == 25
102
+ assert s.category == "standard"
103
+ assert s.tier == "pro"
104
+ assert s.bypass_enabled is False
105
+ assert s.window_hours == 1
106
+ assert s.summary is not None
107
+ assert s.summary["standard"].used == 5
108
+ assert s.summary["standard"].limit == 30
109
+ assert s.summary["agent"].used == 1
110
+ assert s.summary["agent"].limit == 5
@@ -0,0 +1,25 @@
1
+ """VCursor SDK - Generate videos from text, images, and URLs using AI."""
2
+
3
+ from vcursor.client import VCursor, VCursorAsync
4
+ from vcursor.types import (
5
+ SubmitRequest,
6
+ SubmitResponse,
7
+ TaskProgress,
8
+ AgentSubmitRequest,
9
+ AgentProgress,
10
+ CategoryUsage,
11
+ ConcurrencyStatus,
12
+ )
13
+
14
+ __version__ = "1.0.0"
15
+ __all__ = [
16
+ "VCursor",
17
+ "VCursorAsync",
18
+ "SubmitRequest",
19
+ "SubmitResponse",
20
+ "TaskProgress",
21
+ "AgentSubmitRequest",
22
+ "AgentProgress",
23
+ "CategoryUsage",
24
+ "ConcurrencyStatus",
25
+ ]