raillog-cli 0.1.0__py3-none-any.whl
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.
- raillog/__init__.py +1 -0
- raillog/cli.py +54 -0
- raillog/client.py +36 -0
- raillog/cmd_auth.py +92 -0
- raillog/cmd_bauzuege.py +834 -0
- raillog/cmd_context.py +68 -0
- raillog/cmd_install.py +100 -0
- raillog/cmd_projects.py +114 -0
- raillog/cmd_queries.py +244 -0
- raillog/cmd_restrictions.py +188 -0
- raillog/cmd_stations.py +209 -0
- raillog/cmd_tracks.py +231 -0
- raillog/cmd_travels.py +573 -0
- raillog/cmd_waggons.py +777 -0
- raillog/data/AGENTS.md +681 -0
- raillog/guard.py +231 -0
- raillog/session.py +114 -0
- raillog_cli-0.1.0.dist-info/METADATA +87 -0
- raillog_cli-0.1.0.dist-info/RECORD +22 -0
- raillog_cli-0.1.0.dist-info/WHEEL +5 -0
- raillog_cli-0.1.0.dist-info/entry_points.txt +2 -0
- raillog_cli-0.1.0.dist-info/top_level.txt +1 -0
raillog/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
raillog/cli.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
raillog — main CLI entry point.
|
|
3
|
+
|
|
4
|
+
Registers all command groups. This is the `raillog` command installed by pip.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from raillog import __version__
|
|
13
|
+
from raillog.cmd_auth import auth_group
|
|
14
|
+
from raillog.cmd_projects import project_group
|
|
15
|
+
from raillog.cmd_context import context_cmd
|
|
16
|
+
from raillog.cmd_stations import station_group
|
|
17
|
+
from raillog.cmd_tracks import track_group
|
|
18
|
+
from raillog.cmd_bauzuege import bauzug_group
|
|
19
|
+
from raillog.cmd_waggons import waggon_group
|
|
20
|
+
from raillog.cmd_travels import travel_group
|
|
21
|
+
from raillog.cmd_restrictions import restriction_group
|
|
22
|
+
from raillog.cmd_queries import query_group
|
|
23
|
+
from raillog.cmd_install import install_skill
|
|
24
|
+
|
|
25
|
+
console = Console()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group()
|
|
29
|
+
@click.version_option(__version__, prog_name="raillog")
|
|
30
|
+
def cli() -> None:
|
|
31
|
+
"""
|
|
32
|
+
Raillog V2.0 — railway construction logistics CLI.
|
|
33
|
+
|
|
34
|
+
\b
|
|
35
|
+
Quick start:
|
|
36
|
+
raillog auth login
|
|
37
|
+
raillog project list
|
|
38
|
+
raillog project select <n>
|
|
39
|
+
raillog context
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ── Register all command groups ───────────────────────────────────────────────
|
|
44
|
+
cli.add_command(auth_group)
|
|
45
|
+
cli.add_command(project_group)
|
|
46
|
+
cli.add_command(context_cmd)
|
|
47
|
+
cli.add_command(station_group)
|
|
48
|
+
cli.add_command(track_group)
|
|
49
|
+
cli.add_command(bauzug_group)
|
|
50
|
+
cli.add_command(waggon_group)
|
|
51
|
+
cli.add_command(travel_group)
|
|
52
|
+
cli.add_command(restriction_group)
|
|
53
|
+
cli.add_command(query_group)
|
|
54
|
+
cli.add_command(install_skill)
|
raillog/client.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Supabase client factory.
|
|
3
|
+
|
|
4
|
+
Builds a supabase-py client and injects the stored JWT so every
|
|
5
|
+
request is authenticated as the logged-in user (respecting RLS).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from supabase import Client, create_client
|
|
11
|
+
|
|
12
|
+
SUPABASE_URL = "https://ouilcwrgxsirpvkzsdkq.supabase.co"
|
|
13
|
+
SUPABASE_ANON_KEY = (
|
|
14
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
|
|
15
|
+
".eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im91aWxjd3JneHNpcnB2a3pzZGtxIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjU4MzMzNzYsImV4cCI6MjA4MTQwOTM3Nn0"
|
|
16
|
+
".WRR4puUXDvS46w7rsc1sHT6cz8_A1pL-1yzK47v7aqI"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_client(access_token: str | None = None) -> Client:
|
|
21
|
+
"""
|
|
22
|
+
Return a Supabase client.
|
|
23
|
+
If access_token is provided, set it on the client so RLS applies.
|
|
24
|
+
"""
|
|
25
|
+
sb = create_client(SUPABASE_URL, SUPABASE_ANON_KEY)
|
|
26
|
+
if access_token:
|
|
27
|
+
# Inject user JWT — required for RLS to work correctly
|
|
28
|
+
sb.postgrest.auth(access_token)
|
|
29
|
+
return sb
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def authed_client() -> Client:
|
|
33
|
+
"""Shortcut: load session and return authenticated client."""
|
|
34
|
+
from raillog import session as sess
|
|
35
|
+
s = sess.require_auth()
|
|
36
|
+
return get_client(s["access_token"])
|
raillog/cmd_auth.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""raillog auth {login,status,logout}"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
from raillog import session as sess
|
|
11
|
+
from raillog.client import get_client, SUPABASE_URL
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.group("auth")
|
|
17
|
+
def auth_group() -> None:
|
|
18
|
+
"""Authenticate with Raillog (Supabase)."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@auth_group.command("login")
|
|
22
|
+
def auth_login() -> None:
|
|
23
|
+
"""Log in with email and password."""
|
|
24
|
+
console.print("[bold]Raillog Login[/bold]")
|
|
25
|
+
email = click.prompt("Email")
|
|
26
|
+
password = click.prompt("Password", hide_input=True)
|
|
27
|
+
|
|
28
|
+
sb = get_client()
|
|
29
|
+
try:
|
|
30
|
+
result = sb.auth.sign_in_with_password({"email": email, "password": password})
|
|
31
|
+
except Exception as e:
|
|
32
|
+
raise SystemExit(f"Login failed: {e}") from e
|
|
33
|
+
|
|
34
|
+
if not result.session:
|
|
35
|
+
raise SystemExit("Login failed: no session returned.")
|
|
36
|
+
|
|
37
|
+
s = result.session
|
|
38
|
+
user = result.user
|
|
39
|
+
|
|
40
|
+
sess.save({
|
|
41
|
+
"access_token": s.access_token,
|
|
42
|
+
"refresh_token": s.refresh_token,
|
|
43
|
+
"expires_at": s.expires_at or int(time.time()) + 3600,
|
|
44
|
+
"user_id": str(user.id) if user else "",
|
|
45
|
+
"user_email": user.email or email,
|
|
46
|
+
"project_id": None,
|
|
47
|
+
"project_name": None,
|
|
48
|
+
"access_level": None,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
console.print(f"[green]Logged in as[/green] [bold]{user.email}[/bold]")
|
|
52
|
+
console.print("Run [cyan]raillog project list[/cyan] to select a project.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@auth_group.command("status")
|
|
56
|
+
def auth_status() -> None:
|
|
57
|
+
"""Show current authentication status."""
|
|
58
|
+
s = sess.load()
|
|
59
|
+
if not s:
|
|
60
|
+
console.print("[red]Not authenticated.[/red] Run: raillog auth login")
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if not sess.is_valid(s):
|
|
64
|
+
console.print("[yellow]Session expired.[/yellow] Run: raillog auth login")
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
remaining = s.get("expires_at", 0) - int(time.time())
|
|
68
|
+
hours = remaining // 3600
|
|
69
|
+
console.print(f"[green]Authenticated[/green] as [bold]{s.get('user_email')}[/bold]")
|
|
70
|
+
console.print(f"Session expires in ~{hours}h")
|
|
71
|
+
if s.get("project_id"):
|
|
72
|
+
console.print(f"Active project: [bold]{s.get('project_name')}[/bold] ({s.get('project_id')})")
|
|
73
|
+
else:
|
|
74
|
+
console.print("[dim]No project selected.[/dim]")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@auth_group.command("refresh")
|
|
78
|
+
def auth_refresh() -> None:
|
|
79
|
+
"""Silently renew the session using the stored refresh token."""
|
|
80
|
+
if sess._try_refresh():
|
|
81
|
+
s = sess.load()
|
|
82
|
+
remaining = ((s or {}).get("expires_at", 0) - int(time.time())) // 3600
|
|
83
|
+
console.print(f"[green]Session refreshed.[/green] Expires in ~{remaining}h")
|
|
84
|
+
else:
|
|
85
|
+
raise SystemExit("Refresh failed — run: raillog auth login")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@auth_group.command("logout")
|
|
89
|
+
def auth_logout() -> None:
|
|
90
|
+
"""Clear the local session."""
|
|
91
|
+
sess.clear()
|
|
92
|
+
console.print("[green]Logged out.[/green]")
|