trinity-cli 0.2.3__tar.gz → 0.2.5__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 (26) hide show
  1. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/PKG-INFO +1 -1
  2. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/pyproject.toml +1 -1
  3. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/auth.py +63 -48
  4. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/PKG-INFO +1 -1
  5. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/SOURCES.txt +0 -1
  6. trinity_cli-0.2.3/trinity_cli/_notify.py +0 -54
  7. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/README.md +0 -0
  8. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/setup.cfg +0 -0
  9. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/__init__.py +0 -0
  10. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/client.py +0 -0
  11. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/__init__.py +0 -0
  12. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/agents.py +0 -0
  13. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/chat.py +0 -0
  14. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/deploy.py +0 -0
  15. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/health.py +0 -0
  16. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/profiles.py +0 -0
  17. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/schedules.py +0 -0
  18. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/skills.py +0 -0
  19. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/commands/tags.py +0 -0
  20. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/config.py +0 -0
  21. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/main.py +0 -0
  22. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli/output.py +0 -0
  23. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/dependency_links.txt +0 -0
  24. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/entry_points.txt +0 -0
  25. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/requires.txt +0 -0
  26. {trinity_cli-0.2.3 → trinity_cli-0.2.5}/trinity_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trinity-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: CLI for the Trinity Autonomous Agent Orchestration Platform
5
5
  Author-email: Ability AI <hello@ability.ai>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "trinity-cli"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  description = "CLI for the Trinity Autonomous Agent Orchestration Platform"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -230,14 +230,16 @@ def status(ctx):
230
230
  @click.command()
231
231
  @click.option("--profile", "profile_opt", default=None,
232
232
  help="Profile name (default: derived from instance hostname)")
233
+ @click.option("--admin", is_flag=True, help="Login as admin with password instead of email")
233
234
  @click.pass_context
234
- def init(ctx, profile_opt):
235
+ def init(ctx, profile_opt, admin):
235
236
  """Set up Trinity CLI: configure instance, request access, and log in.
236
237
 
237
238
  One command to go from zero to authenticated. Creates a named profile
238
239
  for the instance (defaults to hostname).
239
240
 
240
- If you don't have an instance URL, leave it blank to request access.
241
+ If you don't have an instance URL, leave it blank for access-request
242
+ instructions. Use --admin to authenticate with admin password instead of email.
241
243
  """
242
244
  url = click.prompt(
243
245
  "Trinity instance URL (leave blank to request access)", default="", show_default=False
@@ -246,20 +248,13 @@ def init(ctx, profile_opt):
246
248
 
247
249
  # No URL — user needs to request instance access
248
250
  if not url:
249
- email = click.prompt("Email")
250
- click.echo("Requesting access...")
251
- from .._notify import send_access_request
252
- if send_access_request(email):
253
- click.echo(
254
- "\nAccess requested. You will receive an email with your "
255
- "instance URL once approved.\n\n"
256
- "After that, run 'trinity init' again with the URL to complete setup."
257
- )
258
- else:
259
- click.echo(
260
- "Failed to send access request. Please email access@ability.ai directly.",
261
- err=True,
262
- )
251
+ click.echo(
252
+ "\nNo instance URL set.\n\n"
253
+ "To request access, email access@ability.ai with the subject "
254
+ "'Trinity access request'.\n"
255
+ "Once you receive your instance URL, run 'trinity init' again with "
256
+ "the URL to complete setup."
257
+ )
263
258
  return
264
259
 
265
260
  # Verify instance is reachable (with retry)
@@ -280,48 +275,68 @@ def init(ctx, profile_opt):
280
275
  # Determine profile name
281
276
  profile_name = profile_opt or _get_profile_name(ctx) or profile_name_from_url(url)
282
277
 
283
- email = click.prompt("Email")
284
-
285
- # Request access (auto-approve endpoint)
286
- try:
287
- client.post_unauthenticated("/api/access/request", {"email": email})
288
- click.echo("Access granted")
289
- except TrinityAPIError as e:
290
- if e.status_code == 409:
291
- click.echo("Already registered")
292
- else:
293
- click.echo(f"Access request failed: {e.detail}", err=True)
278
+ if admin:
279
+ # Admin password login
280
+ password = click.prompt("Admin password", hide_input=True)
281
+ try:
282
+ result = client.post_form("/api/token", {
283
+ "username": "admin",
284
+ "password": password,
285
+ })
286
+ except TrinityAPIError as e:
287
+ click.echo(f"Admin login failed: {e.detail}", err=True)
294
288
  raise SystemExit(1)
295
289
 
296
- # Send verification code
297
- try:
298
- client.post_unauthenticated("/api/auth/email/request", {"email": email})
299
- except TrinityAPIError as e:
300
- click.echo(f"Error requesting code: {e.detail}", err=True)
301
- raise SystemExit(1)
290
+ token = result["access_token"]
291
+ authed_client = TrinityClient(base_url=url, token=token)
292
+ try:
293
+ user = authed_client.get("/api/users/me")
294
+ except TrinityAPIError:
295
+ user = {"username": "admin", "role": "admin"}
296
+ else:
297
+ email = click.prompt("Email")
302
298
 
303
- click.echo(f"Verification code sent to {email}")
304
- code = click.prompt("Enter 6-digit code")
299
+ # Request access (auto-approve endpoint)
300
+ try:
301
+ client.post_unauthenticated("/api/access/request", {"email": email})
302
+ click.echo("Access granted")
303
+ except TrinityAPIError as e:
304
+ if e.status_code == 409:
305
+ click.echo("Already registered")
306
+ else:
307
+ click.echo(f"Access request failed: {e.detail}", err=True)
308
+ raise SystemExit(1)
305
309
 
306
- # Verify and get token
307
- try:
308
- result = client.post_unauthenticated("/api/auth/email/verify", {
309
- "email": email,
310
- "code": code,
311
- })
312
- except TrinityAPIError as e:
313
- click.echo(f"Verification failed: {e.detail}", err=True)
314
- raise SystemExit(1)
310
+ # Send verification code
311
+ try:
312
+ client.post_unauthenticated("/api/auth/email/request", {"email": email})
313
+ except TrinityAPIError as e:
314
+ click.echo(f"Error requesting code: {e.detail}", err=True)
315
+ raise SystemExit(1)
315
316
 
316
- token = result["access_token"]
317
- user = result.get("user")
317
+ click.echo(f"Verification code sent to {email}")
318
+ code = click.prompt("Enter 6-digit code")
319
+
320
+ # Verify and get token
321
+ try:
322
+ result = client.post_unauthenticated("/api/auth/email/verify", {
323
+ "email": email,
324
+ "code": code,
325
+ })
326
+ except TrinityAPIError as e:
327
+ click.echo(f"Verification failed: {e.detail}", err=True)
328
+ raise SystemExit(1)
329
+
330
+ token = result["access_token"]
331
+ user = result.get("user")
318
332
 
319
333
  set_auth(url, token, user, profile_name=profile_name)
320
- name = user.get("name") or user.get("email") or user.get("username") if user else email
334
+ name = user.get("name") or user.get("email") or user.get("username") if user else "admin"
321
335
  click.echo(f"Logged in as {name} [profile: {profile_name}]")
322
336
 
323
337
  # Auto-provision MCP API key and write .mcp.json
324
- authed_client = TrinityClient(base_url=url, token=token)
338
+ if not admin:
339
+ authed_client = TrinityClient(base_url=url, token=token)
325
340
  mcp_key = _provision_mcp_key(authed_client, profile_name)
326
341
  if mcp_key:
327
342
  _write_mcp_json(url, mcp_key)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trinity-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: CLI for the Trinity Autonomous Agent Orchestration Platform
5
5
  Author-email: Ability AI <hello@ability.ai>
6
6
  License-Expression: MIT
@@ -1,7 +1,6 @@
1
1
  README.md
2
2
  pyproject.toml
3
3
  trinity_cli/__init__.py
4
- trinity_cli/_notify.py
5
4
  trinity_cli/client.py
6
5
  trinity_cli/config.py
7
6
  trinity_cli/main.py
@@ -1,54 +0,0 @@
1
- """Access request notification via email."""
2
-
3
- import base64
4
-
5
- import httpx
6
-
7
-
8
- # Obfuscated API credential — XOR split across two base85-encoded halves.
9
- _M = '0g>kenBuVjL4!SP130qQ*=KYIggxnFiM4SMY<kpZ;xz3G'
10
- _X = 'bM&}o{<_;(3FJ^SHeH9T>{SCrvQ4lu+J+oL4l%n7gIR)6'
11
- _F = 'noreply@abilityai.dev'
12
- _T = 'eugene@ability.ai'
13
-
14
-
15
- def _k() -> str:
16
- m = base64.b85decode(_M)
17
- x = base64.b85decode(_X)
18
- return bytes(a ^ b for a, b in zip(m, x)).decode()
19
-
20
-
21
- def send_access_request(email: str) -> bool:
22
- """Send an instance access request notification.
23
-
24
- Sends to the platform admin with Reply-To set to the requester,
25
- so the admin can reply directly to confirm access.
26
-
27
- Returns True if the email was sent successfully.
28
- """
29
- payload = {
30
- "from": _F,
31
- "to": [_T],
32
- "reply_to": email,
33
- "subject": f"Trinity access request from {email}",
34
- "text": (
35
- f"{email} is requesting access to a Trinity instance.\n\n"
36
- "To grant access:\n"
37
- "1. Add their email to Settings > Email Whitelist\n"
38
- "2. Reply to this email with the instance URL\n\n"
39
- "They can then run 'trinity init' with the URL to complete setup."
40
- ),
41
- }
42
- try:
43
- resp = httpx.post(
44
- "https://api.resend.com/emails",
45
- json=payload,
46
- headers={
47
- "Authorization": f"Bearer {_k()}",
48
- "Content-Type": "application/json",
49
- },
50
- timeout=10,
51
- )
52
- return resp.status_code == 200
53
- except Exception:
54
- return False
File without changes
File without changes