litelambda-cli 0.1.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,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: litelambda-cli
3
+ Version: 0.1.0
4
+ Summary: Official CLI for LiteLambda — Serverless Python Cron Job Platform
5
+ Author-email: LiteLambda <support@litelambda.in>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://litelambda.in
8
+ Project-URL: Documentation, https://litelambda.in/docs
9
+ Project-URL: Repository, https://github.com/litelambda/litelambda-cli
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Environment :: Console
13
+ Classifier: Topic :: Software Development :: Build Tools
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+
17
+ # LiteLambda CLI (`litelambda`)
18
+
19
+ Official command-line interface for [LiteLambda](https://litelambda.in) — serverless Python cron job hosting without managing servers.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install litelambda-cli
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Login
30
+ Generate an API token from your [LiteLambda Settings](https://litelambda.in/settings/#api-tokens), then run:
31
+
32
+ ```bash
33
+ litelambda login
34
+ ```
35
+
36
+ ### 2. Check Account
37
+ ```bash
38
+ litelambda whoami
39
+ ```
40
+
41
+ ### 3. Deploy a Python Script
42
+ Deploy any Python file on a cron schedule:
43
+
44
+ ```bash
45
+ litelambda deploy scraper.py --schedule "0 9 * * *" --name "Morning Scraper"
46
+ ```
47
+
48
+ With pip dependencies:
49
+ ```bash
50
+ litelambda deploy bot.py --schedule "*/15 * * * *" --requirements requirements.txt
51
+ ```
52
+
53
+ ### 4. List All Jobs
54
+ ```bash
55
+ litelambda list
56
+ ```
57
+
58
+ ### 5. Run a Job Manually
59
+ ```bash
60
+ litelambda run "Morning Scraper"
61
+ ```
62
+
63
+ ### 6. View Execution Logs
64
+ ```bash
65
+ litelambda logs "Morning Scraper"
66
+ ```
67
+
68
+ ---
69
+
70
+ ## License
71
+ MIT
@@ -0,0 +1,55 @@
1
+ # LiteLambda CLI (`litelambda`)
2
+
3
+ Official command-line interface for [LiteLambda](https://litelambda.in) — serverless Python cron job hosting without managing servers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install litelambda-cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### 1. Login
14
+ Generate an API token from your [LiteLambda Settings](https://litelambda.in/settings/#api-tokens), then run:
15
+
16
+ ```bash
17
+ litelambda login
18
+ ```
19
+
20
+ ### 2. Check Account
21
+ ```bash
22
+ litelambda whoami
23
+ ```
24
+
25
+ ### 3. Deploy a Python Script
26
+ Deploy any Python file on a cron schedule:
27
+
28
+ ```bash
29
+ litelambda deploy scraper.py --schedule "0 9 * * *" --name "Morning Scraper"
30
+ ```
31
+
32
+ With pip dependencies:
33
+ ```bash
34
+ litelambda deploy bot.py --schedule "*/15 * * * *" --requirements requirements.txt
35
+ ```
36
+
37
+ ### 4. List All Jobs
38
+ ```bash
39
+ litelambda list
40
+ ```
41
+
42
+ ### 5. Run a Job Manually
43
+ ```bash
44
+ litelambda run "Morning Scraper"
45
+ ```
46
+
47
+ ### 6. View Execution Logs
48
+ ```bash
49
+ litelambda logs "Morning Scraper"
50
+ ```
51
+
52
+ ---
53
+
54
+ ## License
55
+ MIT
@@ -0,0 +1,6 @@
1
+ """
2
+ LiteLambda CLI
3
+ Official CLI client for LiteLambda (https://litelambda.in)
4
+ """
5
+
6
+ __version__ = "0.1.0"
@@ -0,0 +1,82 @@
1
+ """
2
+ cli/litelambda/client.py
3
+ Zero-dependency HTTP client for LiteLambda REST API.
4
+ """
5
+ import json
6
+ import urllib.request
7
+ import urllib.error
8
+ import urllib.parse
9
+ from typing import Dict, Any, Optional
10
+ from litelambda.config import get_api_url, get_api_token
11
+
12
+
13
+ class APIError(Exception):
14
+ def __init__(self, message: str, status_code: Optional[int] = None, error_code: Optional[str] = None):
15
+ super().__init__(message)
16
+ self.status_code = status_code
17
+ self.error_code = error_code
18
+
19
+
20
+ class LiteLambdaClient:
21
+ def __init__(self, token: Optional[str] = None, base_url: Optional[str] = None):
22
+ self.token = token or get_api_token()
23
+ self.base_url = (base_url or get_api_url()).rstrip("/")
24
+
25
+ def _request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
26
+ url = f"{self.base_url}/{endpoint.lstrip('/')}"
27
+ headers = {
28
+ "User-Agent": "litelambda-cli/0.1.0",
29
+ "Accept": "application/json",
30
+ }
31
+
32
+ if self.token:
33
+ headers["Authorization"] = f"Bearer {self.token}"
34
+
35
+ body_bytes = None
36
+ if data is not None:
37
+ headers["Content-Type"] = "application/json"
38
+ body_bytes = json.dumps(data).encode("utf-8")
39
+
40
+ req = urllib.request.Request(url, data=body_bytes, headers=headers, method=method.upper())
41
+
42
+ try:
43
+ with urllib.request.urlopen(req, timeout=30) as response:
44
+ resp_data = response.read().decode("utf-8")
45
+ if resp_data:
46
+ return json.loads(resp_data)
47
+ return {}
48
+ except urllib.error.HTTPError as e:
49
+ raw_err = e.read().decode("utf-8")
50
+ err_msg = f"HTTP {e.code}: {e.reason}"
51
+ err_code = None
52
+ try:
53
+ parsed = json.loads(raw_err)
54
+ if isinstance(parsed, dict):
55
+ err_msg = parsed.get("message") or parsed.get("error") or err_msg
56
+ err_code = parsed.get("error_code")
57
+ except Exception:
58
+ if raw_err:
59
+ err_msg = f"{err_msg} - {raw_err[:200]}"
60
+ raise APIError(err_msg, status_code=e.code, error_code=err_code)
61
+ except urllib.error.URLError as e:
62
+ raise APIError(f"Network error connecting to {self.base_url}: {e.reason}")
63
+ except Exception as e:
64
+ raise APIError(f"Unexpected error: {str(e)}")
65
+
66
+ def verify_auth(self) -> Dict[str, Any]:
67
+ return self._request("GET", "/auth/verify")
68
+
69
+ def list_crons(self) -> Dict[str, Any]:
70
+ return self._request("GET", "/crons")
71
+
72
+ def get_cron(self, id_or_name: str) -> Dict[str, Any]:
73
+ return self._request("GET", f"/crons/{urllib.parse.quote(id_or_name)}")
74
+
75
+ def deploy_cron(self, payload: Dict[str, Any]) -> Dict[str, Any]:
76
+ return self._request("POST", "/crons", data=payload)
77
+
78
+ def run_cron(self, id_or_name: str) -> Dict[str, Any]:
79
+ return self._request("POST", f"/crons/{urllib.parse.quote(id_or_name)}/run")
80
+
81
+ def get_logs(self, id_or_name: str) -> Dict[str, Any]:
82
+ return self._request("GET", f"/crons/{urllib.parse.quote(id_or_name)}/logs")
@@ -0,0 +1,57 @@
1
+ """
2
+ cli/litelambda/config.py
3
+ Local configuration and credential management (~/.litelambda/credentials.json).
4
+ """
5
+ import os
6
+ import json
7
+ from pathlib import Path
8
+
9
+ DEFAULT_API_URL = "https://litelambda.in/api/v1"
10
+ CONFIG_DIR = Path.home() / ".litelambda"
11
+ CREDENTIALS_FILE = CONFIG_DIR / "credentials.json"
12
+
13
+
14
+ def get_api_url() -> str:
15
+ """Returns the API base URL, checking env var LITELAMBDA_API_URL first."""
16
+ return os.environ.get("LITELAMBDA_API_URL", DEFAULT_API_URL).rstrip("/")
17
+
18
+
19
+ def get_api_token() -> str | None:
20
+ """Returns the API token from env var or credentials file."""
21
+ env_token = os.environ.get("LITELAMBDA_API_TOKEN")
22
+ if env_token:
23
+ return env_token.strip()
24
+
25
+ if not CREDENTIALS_FILE.exists():
26
+ return None
27
+
28
+ try:
29
+ with open(CREDENTIALS_FILE, "r", encoding="utf-8") as f:
30
+ data = json.load(f)
31
+ return data.get("api_token")
32
+ except Exception:
33
+ return None
34
+
35
+
36
+ def save_credentials(token: str, user_email: str | None = None) -> None:
37
+ """Saves API token to ~/.litelambda/credentials.json."""
38
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
39
+ payload = {
40
+ "api_token": token.strip(),
41
+ "user_email": user_email,
42
+ "api_url": get_api_url(),
43
+ }
44
+ with open(CREDENTIALS_FILE, "w", encoding="utf-8") as f:
45
+ json.dump(payload, f, indent=2)
46
+
47
+ try:
48
+ # Secure file permissions (owner rw only)
49
+ os.chmod(CREDENTIALS_FILE, 0o600)
50
+ except Exception:
51
+ pass
52
+
53
+
54
+ def clear_credentials() -> None:
55
+ """Removes stored credentials."""
56
+ if CREDENTIALS_FILE.exists():
57
+ CREDENTIALS_FILE.unlink()
@@ -0,0 +1,307 @@
1
+ """
2
+ cli/litelambda/main.py
3
+ CLI entrypoint for LiteLambda (litelambda-cli).
4
+ """
5
+ import sys
6
+ import os
7
+ import argparse
8
+ from pathlib import Path
9
+
10
+ # Add package parent to sys.path if running directly as script
11
+ pkg_parent = str(Path(__file__).resolve().parent.parent)
12
+ if pkg_parent not in sys.path:
13
+ sys.path.insert(0, pkg_parent)
14
+
15
+ from litelambda.client import LiteLambdaClient, APIError
16
+ from litelambda.config import (
17
+ get_api_token,
18
+ save_credentials,
19
+ clear_credentials,
20
+ get_api_url,
21
+ )
22
+
23
+ # Terminal styling helpers
24
+ BOLD = "\033[1m"
25
+ DIM = "\033[2m"
26
+ GREEN = "\033[32m"
27
+ CYAN = "\033[36m"
28
+ YELLOW = "\033[33m"
29
+ RED = "\033[31m"
30
+ RESET = "\033[0m"
31
+
32
+
33
+ def print_success(msg: str):
34
+ print(f"{GREEN}✔{RESET} {msg}")
35
+
36
+
37
+ def print_error(msg: str):
38
+ print(f"{RED}✖ Error:{RESET} {msg}", file=sys.stderr)
39
+
40
+
41
+ def print_warning(msg: str):
42
+ print(f"{YELLOW}⚠{RESET} {msg}")
43
+
44
+
45
+ def print_header(msg: str):
46
+ print(f"{BOLD}{CYAN}==>{RESET} {BOLD}{msg}{RESET}")
47
+
48
+
49
+ def cmd_login(args):
50
+ """Log in with an API token."""
51
+ token = args.token
52
+ if not token:
53
+ print(f"\n{BOLD}LiteLambda Authentication{RESET}")
54
+ print(f"Generate your personal API token at: {CYAN}https://litelambda.in/settings/#api-tokens{RESET}\n")
55
+ try:
56
+ token = input(f"{BOLD}Enter your API token (ll_live_...): {RESET}").strip()
57
+ except (KeyboardInterrupt, EOFError):
58
+ print("\nCancelled.")
59
+ sys.exit(1)
60
+
61
+ if not token:
62
+ print_error("Token cannot be empty.")
63
+ sys.exit(1)
64
+
65
+ client = LiteLambdaClient(token=token)
66
+ try:
67
+ data = client.verify_auth()
68
+ user = data.get("user", {})
69
+ email = user.get("email")
70
+ plan = user.get("plan", "").title()
71
+ save_credentials(token, user_email=email)
72
+ print_success(f"Logged in successfully as {BOLD}{email}{RESET} ({plan} plan).")
73
+ print(f"Credentials stored in {DIM}~/.litelambda/credentials.json{RESET}")
74
+ except APIError as e:
75
+ print_error(f"Authentication failed: {e}")
76
+ sys.exit(1)
77
+
78
+
79
+ def cmd_whoami(args):
80
+ """Show current logged-in user and account stats."""
81
+ client = LiteLambdaClient()
82
+ if not client.token:
83
+ print_error("Not logged in. Run `litelambda login` first.")
84
+ sys.exit(1)
85
+
86
+ try:
87
+ data = client.verify_auth()
88
+ u = data.get("user", {})
89
+ t = data.get("token", {})
90
+ print(f"\n{BOLD}LiteLambda Account{RESET}")
91
+ print(f" {DIM}Email:{RESET} {BOLD}{u.get('email')}{RESET}")
92
+ print(f" {DIM}Plan:{RESET} {u.get('plan', '').title()}")
93
+ print(f" {DIM}Credits Left:{RESET} {GREEN}{u.get('credits')}{RESET}")
94
+ print(f" {DIM}Active Crons:{RESET} {u.get('active_crons')}")
95
+ if u.get('trial_days_remaining') is not None:
96
+ print(f" {DIM}Trial Days:{RESET} {YELLOW}{u.get('trial_days_remaining')} days left{RESET}")
97
+ print(f" {DIM}Using Token:{RESET} {t.get('name')} ({t.get('prefix')})")
98
+ print()
99
+ except APIError as e:
100
+ print_error(str(e))
101
+ sys.exit(1)
102
+
103
+
104
+ def cmd_list(args):
105
+ """List all deployed cron jobs."""
106
+ client = LiteLambdaClient()
107
+ if not client.token:
108
+ print_error("Not logged in. Run `litelambda login` first.")
109
+ sys.exit(1)
110
+
111
+ try:
112
+ data = client.list_crons()
113
+ crons = data.get("crons", [])
114
+ if not crons:
115
+ print(f"No cron jobs found. Deploy your first job with: {CYAN}litelambda deploy <file.py>{RESET}")
116
+ return
117
+
118
+ print(f"\n{BOLD}Deployed Cron Jobs ({len(crons)}){RESET}")
119
+ # Format table
120
+ header = f"{'NAME':<24} {'SCHEDULE':<16} {'STATUS':<10} {'TIMEOUT':<9} {'LAST RUN':<20}"
121
+ print(f"{DIM}{header}{RESET}")
122
+ print(f"{DIM}{'-' * 80}{RESET}")
123
+ for c in crons:
124
+ status = c.get('status', '').upper()
125
+ status_color = GREEN if status == 'ACTIVE' else YELLOW
126
+ last_run = c.get('last_run_at')
127
+ last_run_str = last_run[:19].replace('T', ' ') if last_run else "Never"
128
+ dur = f" ({c['last_duration_ms']}ms)" if c.get('last_duration_ms') else ""
129
+ print(f"{BOLD}{c['name']:<24}{RESET} {c['schedule']:<16} {status_color}{status:<10}{RESET} {str(c['timeout']) + 's':<9} {last_run_str + dur}")
130
+ print()
131
+ except APIError as e:
132
+ print_error(str(e))
133
+ sys.exit(1)
134
+
135
+
136
+ def cmd_deploy(args):
137
+ """Deploy a Python script to LiteLambda."""
138
+ client = LiteLambdaClient()
139
+ if not client.token:
140
+ print_error("Not logged in. Run `litelambda login` first.")
141
+ sys.exit(1)
142
+
143
+ filepath = Path(args.file)
144
+ if not filepath.exists():
145
+ print_error(f"File not found: {filepath}")
146
+ sys.exit(1)
147
+
148
+ try:
149
+ code = filepath.read_text(encoding="utf-8")
150
+ except Exception as e:
151
+ print_error(f"Failed to read file: {e}")
152
+ sys.exit(1)
153
+
154
+ name = args.name or filepath.stem
155
+ packages = ""
156
+ if args.requirements:
157
+ req_path = Path(args.requirements)
158
+ if not req_path.exists():
159
+ print_error(f"Requirements file not found: {req_path}")
160
+ sys.exit(1)
161
+ packages = req_path.read_text(encoding="utf-8")
162
+
163
+ env_vars = ""
164
+ if args.env:
165
+ env_path = Path(args.env)
166
+ if env_path.exists():
167
+ env_vars = env_path.read_text(encoding="utf-8")
168
+ else:
169
+ # Assume inline KEY=VALUE pairs separated by comma or newline
170
+ env_vars = args.env.replace(",", "\n")
171
+
172
+ payload = {
173
+ "name": name,
174
+ "code": code,
175
+ "schedule": args.schedule,
176
+ "packages": packages,
177
+ "env_vars": env_vars,
178
+ "timeout": args.timeout,
179
+ }
180
+
181
+ print_header(f"Deploying '{name}' to LiteLambda...")
182
+ try:
183
+ res = client.deploy_cron(payload)
184
+ action = res.get("action", "deployed")
185
+ cron = res.get("cron", {})
186
+ print_success(f"Job successfully {action}!")
187
+ print(f" {DIM}ID:{RESET} {cron.get('id')}")
188
+ print(f" {DIM}Schedule:{RESET} {cron.get('schedule')}")
189
+ print(f" {DIM}Timeout:{RESET} {cron.get('timeout')}s")
190
+ print(f" {DIM}Web URL:{RESET} {CYAN}{cron.get('web_url')}{RESET}\n")
191
+ except APIError as e:
192
+ print_error(str(e))
193
+ sys.exit(1)
194
+
195
+
196
+ def cmd_run(args):
197
+ """Trigger manual execution of a cron job."""
198
+ client = LiteLambdaClient()
199
+ if not client.token:
200
+ print_error("Not logged in. Run `litelambda login` first.")
201
+ sys.exit(1)
202
+
203
+ id_or_name = args.cron
204
+ print_header(f"Triggering run for '{id_or_name}'...")
205
+ try:
206
+ res = client.run_cron(id_or_name)
207
+ print_success(res.get("message", "Job triggered."))
208
+ print(f"Check execution logs with: {CYAN}litelambda logs \"{id_or_name}\"{RESET}")
209
+ except APIError as e:
210
+ print_error(str(e))
211
+ sys.exit(1)
212
+
213
+
214
+ def cmd_logs(args):
215
+ """View execution logs for a cron job."""
216
+ client = LiteLambdaClient()
217
+ if not client.token:
218
+ print_error("Not logged in. Run `litelambda login` first.")
219
+ sys.exit(1)
220
+
221
+ id_or_name = args.cron
222
+ try:
223
+ data = client.get_logs(id_or_name)
224
+ executions = data.get("executions", [])
225
+ if not executions:
226
+ print(f"No execution history recorded for '{id_or_name}'.")
227
+ return
228
+
229
+ latest = executions[0]
230
+ status = latest.get("status", "").upper()
231
+ status_color = GREEN if status == "SUCCESS" else (RED if status == "ERROR" else YELLOW)
232
+
233
+ print(f"\n{BOLD}Execution Logs for '{data.get('cron_name')}'{RESET}")
234
+ print(f" {DIM}Started At:{RESET} {latest.get('started_at')}")
235
+ print(f" {DIM}Duration:{RESET} {latest.get('duration_ms')} ms")
236
+ print(f" {DIM}Status:{RESET} {status_color}{status}{RESET}\n")
237
+
238
+ print(f"{DIM}{'─' * 60}{RESET}")
239
+ log_lines = latest.get("log_lines") or []
240
+ if log_lines:
241
+ for l in log_lines:
242
+ t = l.get("t", "")[11:19]
243
+ msg = l.get("msg", "")
244
+ level = l.get("level", "info")
245
+ color = RED if level == "error" else RESET
246
+ print(f"{DIM}[{t}]{RESET} {color}{msg}{RESET}")
247
+ elif latest.get("error_message"):
248
+ print(f"{RED}{latest['error_message']}{RESET}")
249
+ else:
250
+ print(f"{DIM}(Execution finished with no console output){RESET}")
251
+ print(f"{DIM}{'─' * 60}{RESET}\n")
252
+
253
+ except APIError as e:
254
+ print_error(str(e))
255
+ sys.exit(1)
256
+
257
+
258
+ def main():
259
+ parser = argparse.ArgumentParser(
260
+ prog="litelambda",
261
+ description="Official CLI for LiteLambda (https://litelambda.in) — Serverless Python Cron Hosting",
262
+ )
263
+ subparsers = parser.add_subparsers(dest="command", help="Command to run")
264
+
265
+ # login
266
+ p_login = subparsers.add_parser("login", help="Authenticate with an API token")
267
+ p_login.add_argument("--token", "-t", help="API token (ll_live_...)")
268
+ p_login.set_defaults(func=cmd_login)
269
+
270
+ # whoami
271
+ p_whoami = subparsers.add_parser("whoami", help="Show current logged-in account")
272
+ p_whoami.set_defaults(func=cmd_whoami)
273
+
274
+ # list
275
+ p_list = subparsers.add_parser("list", help="List all deployed cron jobs")
276
+ p_list.set_defaults(func=cmd_list)
277
+
278
+ # deploy
279
+ p_deploy = subparsers.add_parser("deploy", help="Deploy a Python script on schedule")
280
+ p_deploy.add_argument("file", help="Path to Python script (.py)")
281
+ p_deploy.add_argument("--schedule", "-s", default="*/5 * * * *", help="Cron schedule expression (default: '*/5 * * * *')")
282
+ p_deploy.add_argument("--name", "-n", help="Cron job name (defaults to filename)")
283
+ p_deploy.add_argument("--requirements", "-r", help="Path to requirements.txt")
284
+ p_deploy.add_argument("--env", "-e", help="Path to .env file or comma-separated KEY=VALUE pairs")
285
+ p_deploy.add_argument("--timeout", type=int, default=30, help="Execution timeout in seconds (default: 30)")
286
+ p_deploy.set_defaults(func=cmd_deploy)
287
+
288
+ # run
289
+ p_run = subparsers.add_parser("run", help="Trigger a cron job execution manually")
290
+ p_run.add_argument("cron", help="Name or UUID of the cron job")
291
+ p_run.set_defaults(func=cmd_run)
292
+
293
+ # logs
294
+ p_logs = subparsers.add_parser("logs", help="View recent execution logs")
295
+ p_logs.add_argument("cron", help="Name or UUID of the cron job")
296
+ p_logs.set_defaults(func=cmd_logs)
297
+
298
+ args = parser.parse_args()
299
+ if not args.command:
300
+ parser.print_help()
301
+ sys.exit(0)
302
+
303
+ args.func(args)
304
+
305
+
306
+ if __name__ == "__main__":
307
+ main()
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: litelambda-cli
3
+ Version: 0.1.0
4
+ Summary: Official CLI for LiteLambda — Serverless Python Cron Job Platform
5
+ Author-email: LiteLambda <support@litelambda.in>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://litelambda.in
8
+ Project-URL: Documentation, https://litelambda.in/docs
9
+ Project-URL: Repository, https://github.com/litelambda/litelambda-cli
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Environment :: Console
13
+ Classifier: Topic :: Software Development :: Build Tools
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+
17
+ # LiteLambda CLI (`litelambda`)
18
+
19
+ Official command-line interface for [LiteLambda](https://litelambda.in) — serverless Python cron job hosting without managing servers.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install litelambda-cli
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Login
30
+ Generate an API token from your [LiteLambda Settings](https://litelambda.in/settings/#api-tokens), then run:
31
+
32
+ ```bash
33
+ litelambda login
34
+ ```
35
+
36
+ ### 2. Check Account
37
+ ```bash
38
+ litelambda whoami
39
+ ```
40
+
41
+ ### 3. Deploy a Python Script
42
+ Deploy any Python file on a cron schedule:
43
+
44
+ ```bash
45
+ litelambda deploy scraper.py --schedule "0 9 * * *" --name "Morning Scraper"
46
+ ```
47
+
48
+ With pip dependencies:
49
+ ```bash
50
+ litelambda deploy bot.py --schedule "*/15 * * * *" --requirements requirements.txt
51
+ ```
52
+
53
+ ### 4. List All Jobs
54
+ ```bash
55
+ litelambda list
56
+ ```
57
+
58
+ ### 5. Run a Job Manually
59
+ ```bash
60
+ litelambda run "Morning Scraper"
61
+ ```
62
+
63
+ ### 6. View Execution Logs
64
+ ```bash
65
+ litelambda logs "Morning Scraper"
66
+ ```
67
+
68
+ ---
69
+
70
+ ## License
71
+ MIT
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ litelambda/__init__.py
4
+ litelambda/client.py
5
+ litelambda/config.py
6
+ litelambda/main.py
7
+ litelambda_cli.egg-info/PKG-INFO
8
+ litelambda_cli.egg-info/SOURCES.txt
9
+ litelambda_cli.egg-info/dependency_links.txt
10
+ litelambda_cli.egg-info/entry_points.txt
11
+ litelambda_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ litelambda = litelambda.main:main
@@ -0,0 +1 @@
1
+ litelambda
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "litelambda-cli"
7
+ version = "0.1.0"
8
+ authors = [
9
+ { name="LiteLambda", email="support@litelambda.in" },
10
+ ]
11
+ description = "Official CLI for LiteLambda — Serverless Python Cron Job Platform"
12
+ readme = "README.md"
13
+ license = "MIT"
14
+ requires-python = ">=3.8"
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ "Environment :: Console",
19
+ "Topic :: Software Development :: Build Tools",
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://litelambda.in"
24
+ Documentation = "https://litelambda.in/docs"
25
+ Repository = "https://github.com/litelambda/litelambda-cli"
26
+
27
+ [project.scripts]
28
+ litelambda = "litelambda.main:main"
29
+
30
+ [tool.setuptools.packages.find]
31
+ where = ["."]
32
+ include = ["litelambda*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+