utim-cli 1.44.9__tar.gz → 1.45.1__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.
- {utim_cli-1.44.9/utim_cli.egg-info → utim_cli-1.45.1}/PKG-INFO +1 -1
- {utim_cli-1.44.9 → utim_cli-1.45.1}/pyproject.toml +1 -1
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/db.py +45 -48
- utim_cli-1.45.1/utim_cli/server/server.py +56 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/utim.py +3 -3
- {utim_cli-1.44.9 → utim_cli-1.45.1/utim_cli.egg-info}/PKG-INFO +1 -1
- utim_cli-1.44.9/utim_cli/server/server.py +0 -56
- {utim_cli-1.44.9 → utim_cli-1.45.1}/CHANGELOG.md +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/LICENSE +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/MANIFEST.in +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/README.md +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/setup.cfg +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/setup.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/__init__.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/agent.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/auth.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/backup.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/blender_agent.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/bootstrap.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/client_utils.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/config.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/constants.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/context_pruner.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/doctor.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/knowledge_graph.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/logger.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/mcp_clean_wrapper.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/mcp_client.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/mcp_registry.json +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/orchestrator.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/reflection.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/report.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/scrapy_search.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/__init__.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/auth.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/email_utils.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/firebase.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/history.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/logging_config.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/models.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/rate_limit.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/router.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/__init__.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/auth_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/completion_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/credit_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/quota_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/session_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/server/routes/share_routes.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/share.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/share_tui.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/situational_scoring.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/state.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tools.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/__init__.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/history_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/mcp_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/model_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/resume_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/tools_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/tui/update_dialog.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/vector_memory.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli/workspace.py +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli.egg-info/SOURCES.txt +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli.egg-info/dependency_links.txt +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli.egg-info/entry_points.txt +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli.egg-info/requires.txt +0 -0
- {utim_cli-1.44.9 → utim_cli-1.45.1}/utim_cli.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "utim-cli"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.45.1"
|
|
8
8
|
description = "UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -401,9 +401,13 @@ def init_db() -> None:
|
|
|
401
401
|
import logging as _logging
|
|
402
402
|
_mig_log = _logging.getLogger("utim.db.migration")
|
|
403
403
|
|
|
404
|
+
print("[DB INIT] init_db() starting...")
|
|
404
405
|
try:
|
|
406
|
+
print(f"[DB INIT] Connecting to DB: {engine.url.drivername} (host: {engine.url.host})")
|
|
405
407
|
Base.metadata.create_all(bind=engine)
|
|
408
|
+
print("[DB INIT] create_all() completed.")
|
|
406
409
|
except Exception as exc:
|
|
410
|
+
print(f"[DB INIT] create_all() failed: {exc}")
|
|
407
411
|
_mig_log.warning(f"Skipping table creation (database might be unavailable): {exc}")
|
|
408
412
|
return
|
|
409
413
|
|
|
@@ -412,70 +416,62 @@ def init_db() -> None:
|
|
|
412
416
|
from sqlalchemy import text, inspect as sa_inspect
|
|
413
417
|
is_postgres = DATABASE_URL.startswith("postgresql")
|
|
414
418
|
|
|
415
|
-
|
|
419
|
+
try:
|
|
420
|
+
inspector = sa_inspect(engine)
|
|
421
|
+
existing_tables = inspector.get_table_names()
|
|
422
|
+
except Exception as inspect_exc:
|
|
423
|
+
print(f"[DB INIT] DB inspection failed (might be normal on new DB): {inspect_exc}")
|
|
424
|
+
existing_tables = []
|
|
425
|
+
|
|
426
|
+
def _col_exists(table_name: str, col_name: str) -> bool:
|
|
427
|
+
if table_name not in existing_tables:
|
|
428
|
+
return False
|
|
429
|
+
try:
|
|
430
|
+
columns = [c["name"] for c in inspector.get_columns(table_name)]
|
|
431
|
+
return col_name in columns
|
|
432
|
+
except Exception:
|
|
433
|
+
return False
|
|
434
|
+
|
|
435
|
+
def _run_migration(table_name: str, col_name: str, sql: str, label: str):
|
|
436
|
+
if _col_exists(table_name, col_name):
|
|
437
|
+
print(f"[DB INIT] Column {table_name}.{col_name} already exists. Skipping.")
|
|
438
|
+
return
|
|
439
|
+
|
|
440
|
+
print(f"[DB INIT] Running migration: {label}")
|
|
416
441
|
try:
|
|
417
442
|
with engine.begin() as _conn:
|
|
443
|
+
if is_postgres:
|
|
444
|
+
# Never hang startup for lock queues: fail fast if blocked for > 3s
|
|
445
|
+
_conn.execute(text("SET lock_timeout = 3000"))
|
|
418
446
|
_conn.execute(text(sql))
|
|
447
|
+
print(f"[DB INIT] Migration OK: {label}")
|
|
419
448
|
_mig_log.info(f"Migration OK: {label}")
|
|
420
449
|
except Exception as _exc:
|
|
421
|
-
|
|
450
|
+
print(f"[DB INIT] Migration skipped/failed ({label}): {_exc}")
|
|
422
451
|
_mig_log.debug(f"Migration skipped ({label}): {_exc}")
|
|
423
452
|
|
|
424
453
|
if is_postgres:
|
|
425
|
-
|
|
426
|
-
_run_migration(
|
|
427
|
-
"ALTER TABLE user_subscriptions ADD COLUMN IF NOT EXISTS refills_processed INTEGER DEFAULT 0 NOT NULL",
|
|
428
|
-
"add refills_processed"
|
|
429
|
-
)
|
|
430
|
-
_run_migration(
|
|
431
|
-
"ALTER TABLE user_subscriptions ADD COLUMN IF NOT EXISTS last_refill_at TIMESTAMP",
|
|
432
|
-
"add last_refill_at"
|
|
433
|
-
)
|
|
434
|
-
_run_migration(
|
|
435
|
-
"ALTER TABLE user_subscriptions ADD COLUMN IF NOT EXISTS current_cycle_used DOUBLE PRECISION DEFAULT 0.0 NOT NULL",
|
|
436
|
-
"add current_cycle_used"
|
|
437
|
-
)
|
|
438
|
-
_run_migration(
|
|
439
|
-
"ALTER TABLE credits ADD COLUMN IF NOT EXISTS bonus_balance DOUBLE PRECISION DEFAULT 0.0 NOT NULL",
|
|
440
|
-
"add bonus_balance"
|
|
441
|
-
)
|
|
442
|
-
_run_migration(
|
|
443
|
-
"ALTER TABLE credits ADD COLUMN IF NOT EXISTS bonus_limit DOUBLE PRECISION DEFAULT 0.0 NOT NULL",
|
|
444
|
-
"add bonus_limit"
|
|
445
|
-
)
|
|
446
|
-
_run_migration(
|
|
447
|
-
"ALTER TABLE email_tracking ADD COLUMN IF NOT EXISTS low_quota_email_sent_at TIMESTAMP",
|
|
448
|
-
"add low_quota_email_sent_at"
|
|
449
|
-
)
|
|
450
|
-
_run_migration(
|
|
451
|
-
"ALTER TABLE email_tracking ADD COLUMN IF NOT EXISTS exhausted_email_sent_at TIMESTAMP",
|
|
452
|
-
"add exhausted_email_sent_at"
|
|
453
|
-
)
|
|
454
|
-
_run_migration(
|
|
455
|
-
"ALTER TABLE email_tracking ADD COLUMN IF NOT EXISTS bonus_email_sent_at TIMESTAMP",
|
|
456
|
-
"add bonus_email_sent_at"
|
|
457
|
-
)
|
|
458
|
-
_run_migration(
|
|
459
|
-
"ALTER TABLE users ADD COLUMN IF NOT EXISTS last_project_folder TEXT",
|
|
460
|
-
"add last_project_folder"
|
|
461
|
-
)
|
|
454
|
+
print("[DB INIT] Postgres detected. Bypassing ALTER TABLE migrations (already applied in production).")
|
|
462
455
|
else:
|
|
463
456
|
# SQLite: no IF NOT EXISTS on ADD COLUMN, swallow duplicate errors
|
|
464
|
-
_run_migration("ALTER TABLE user_subscriptions ADD COLUMN refills_processed INTEGER DEFAULT 0 NOT NULL", "sqlite add refills_processed")
|
|
465
|
-
_run_migration("ALTER TABLE user_subscriptions ADD COLUMN last_refill_at TIMESTAMP", "sqlite add last_refill_at")
|
|
466
|
-
_run_migration("ALTER TABLE user_subscriptions ADD COLUMN current_cycle_used FLOAT DEFAULT 0.0 NOT NULL", "sqlite add current_cycle_used")
|
|
467
|
-
_run_migration("ALTER TABLE credits ADD COLUMN bonus_balance FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_balance")
|
|
468
|
-
_run_migration("ALTER TABLE credits ADD COLUMN bonus_limit FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_limit")
|
|
469
|
-
_run_migration("ALTER TABLE email_tracking ADD COLUMN low_quota_email_sent_at TIMESTAMP", "sqlite add low_quota_email_sent_at")
|
|
470
|
-
_run_migration("ALTER TABLE email_tracking ADD COLUMN exhausted_email_sent_at TIMESTAMP", "sqlite add exhausted_email_sent_at")
|
|
471
|
-
_run_migration("ALTER TABLE email_tracking ADD COLUMN bonus_email_sent_at TIMESTAMP", "sqlite add bonus_email_sent_at")
|
|
472
|
-
_run_migration("ALTER TABLE users ADD COLUMN last_project_folder TEXT", "sqlite add last_project_folder")
|
|
457
|
+
_run_migration("user_subscriptions", "refills_processed", "ALTER TABLE user_subscriptions ADD COLUMN refills_processed INTEGER DEFAULT 0 NOT NULL", "sqlite add refills_processed")
|
|
458
|
+
_run_migration("user_subscriptions", "last_refill_at", "ALTER TABLE user_subscriptions ADD COLUMN last_refill_at TIMESTAMP", "sqlite add last_refill_at")
|
|
459
|
+
_run_migration("user_subscriptions", "current_cycle_used", "ALTER TABLE user_subscriptions ADD COLUMN current_cycle_used FLOAT DEFAULT 0.0 NOT NULL", "sqlite add current_cycle_used")
|
|
460
|
+
_run_migration("credits", "bonus_balance", "ALTER TABLE credits ADD COLUMN bonus_balance FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_balance")
|
|
461
|
+
_run_migration("credits", "bonus_limit", "ALTER TABLE credits ADD COLUMN bonus_limit FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_limit")
|
|
462
|
+
_run_migration("email_tracking", "low_quota_email_sent_at", "ALTER TABLE email_tracking ADD COLUMN low_quota_email_sent_at TIMESTAMP", "sqlite add low_quota_email_sent_at")
|
|
463
|
+
_run_migration("email_tracking", "exhausted_email_sent_at", "ALTER TABLE email_tracking ADD COLUMN exhausted_email_sent_at TIMESTAMP", "sqlite add exhausted_email_sent_at")
|
|
464
|
+
_run_migration("email_tracking", "bonus_email_sent_at", "ALTER TABLE email_tracking ADD COLUMN bonus_email_sent_at TIMESTAMP", "sqlite add bonus_email_sent_at")
|
|
465
|
+
_run_migration("users", "last_project_folder", "ALTER TABLE users ADD COLUMN last_project_folder TEXT", "sqlite add last_project_folder")
|
|
473
466
|
|
|
474
467
|
# Seed the plans if they don't exist
|
|
468
|
+
print("[DB INIT] Seeding plans checking...")
|
|
475
469
|
db = SessionLocal()
|
|
476
470
|
try:
|
|
477
471
|
free_plan = db.query(Plan).filter(Plan.name == "free").first()
|
|
472
|
+
print(f"[DB INIT] Free plan query done. Exists: {bool(free_plan)}")
|
|
478
473
|
if not free_plan:
|
|
474
|
+
print("[DB INIT] Creating new plans...")
|
|
479
475
|
plans = [
|
|
480
476
|
Plan(
|
|
481
477
|
id="free",
|
|
@@ -594,6 +590,7 @@ def init_db() -> None:
|
|
|
594
590
|
pass
|
|
595
591
|
finally:
|
|
596
592
|
db.close()
|
|
593
|
+
print("[DB INIT] init_db() completed successfully.")
|
|
597
594
|
|
|
598
595
|
|
|
599
596
|
def get_db():
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
UTIM Production Server — Entry Point
|
|
3
|
+
Run locally: python -m utim_cli.server.server
|
|
4
|
+
Railway runs: uvicorn utim_cli.server.router:app --host 0.0.0.0 --port $PORT
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
# Ensure parent and grandparent directories are in sys.path to import 'utim_cli'
|
|
12
|
+
_dir = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
for _pd in [os.path.dirname(os.path.dirname(_dir)), os.path.dirname(_dir)]:
|
|
14
|
+
if _pd and _pd not in sys.path:
|
|
15
|
+
sys.path.insert(0, _pd)
|
|
16
|
+
|
|
17
|
+
import uvicorn
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main():
|
|
21
|
+
host = os.environ.get("HOST", "0.0.0.0")
|
|
22
|
+
port = int(os.environ.get("PORT", 8080))
|
|
23
|
+
|
|
24
|
+
# Warn about missing env vars but DO NOT exit — server must start
|
|
25
|
+
required = {
|
|
26
|
+
"DATABASE_URL": os.environ.get("DATABASE_URL"),
|
|
27
|
+
"OPENROUTER_API_KEY": os.environ.get("OPENROUTER_API_KEY"),
|
|
28
|
+
"UTIM_MASTER_KEY": os.environ.get("UTIM_MASTER_KEY"),
|
|
29
|
+
}
|
|
30
|
+
missing = [k for k, v in required.items() if not v]
|
|
31
|
+
if missing:
|
|
32
|
+
print(f"[WARNING] Missing env vars: {', '.join(missing)} — some features will be degraded.")
|
|
33
|
+
print(" Set these in Railway → Service → Variables")
|
|
34
|
+
|
|
35
|
+
print(f"🚀 UTIM Production Server")
|
|
36
|
+
print(f" http://{host}:{port}")
|
|
37
|
+
print(f" Docs: http://{host}:{port}/docs")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
uvicorn.run(
|
|
41
|
+
"utim_cli.server.router:app",
|
|
42
|
+
host=host,
|
|
43
|
+
port=port,
|
|
44
|
+
reload=False,
|
|
45
|
+
workers=1,
|
|
46
|
+
# Do NOT pass log_config=None — keep default logging so errors are visible
|
|
47
|
+
)
|
|
48
|
+
except Exception as exc:
|
|
49
|
+
print(f"[FATAL] uvicorn failed to start: {exc}", file=sys.stderr)
|
|
50
|
+
import traceback
|
|
51
|
+
traceback.print_exc()
|
|
52
|
+
sys.exit(1)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
main()
|
|
@@ -585,7 +585,7 @@ def _print_animated_banner():
|
|
|
585
585
|
# Speed up for spaces to make it feel more like typing
|
|
586
586
|
time.sleep(0.002 if char == " " else 0.005)
|
|
587
587
|
|
|
588
|
-
console.print(f"\n [bold white]U Think I Make[/bold white] [dim]v1.
|
|
588
|
+
console.print(f"\n [bold white]U Think I Make[/bold white] [dim]v1.45.1[/dim]")
|
|
589
589
|
user_email = config.email
|
|
590
590
|
user_type = "UTIM Community"
|
|
591
591
|
api_key = config.get("api_key")
|
|
@@ -2691,7 +2691,7 @@ def check_and_update_background():
|
|
|
2691
2691
|
return
|
|
2692
2692
|
|
|
2693
2693
|
latest_ver = resp.json().get("version", "")
|
|
2694
|
-
current_ver = "1.
|
|
2694
|
+
current_ver = "1.45.1"
|
|
2695
2695
|
|
|
2696
2696
|
def parse_ver(v):
|
|
2697
2697
|
return [int(x) for x in v.split(".") if x.isdigit()]
|
|
@@ -2887,7 +2887,7 @@ app = typer.Typer()
|
|
|
2887
2887
|
def version_callback(value: bool):
|
|
2888
2888
|
if value:
|
|
2889
2889
|
import typer
|
|
2890
|
-
print("U Think I Make v1.
|
|
2890
|
+
print("U Think I Make v1.45.1")
|
|
2891
2891
|
raise typer.Exit()
|
|
2892
2892
|
|
|
2893
2893
|
@app.callback(invoke_without_command=True)
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
UTIM Production Server — Entry Point
|
|
3
|
-
Run locally: python -m utim_cli.server.server
|
|
4
|
-
Railway runs: uvicorn utim_cli.server.router:app --host 0.0.0.0 --port $PORT
|
|
5
|
-
"""
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
import sys
|
|
9
|
-
import os
|
|
10
|
-
|
|
11
|
-
# Ensure parent and grandparent directories are in sys.path to import 'utim_cli'
|
|
12
|
-
_dir = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
-
for _pd in [os.path.dirname(os.path.dirname(_dir)), os.path.dirname(_dir)]:
|
|
14
|
-
if _pd and _pd not in sys.path:
|
|
15
|
-
sys.path.insert(0, _pd)
|
|
16
|
-
|
|
17
|
-
import argparse
|
|
18
|
-
import uvicorn
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def main():
|
|
22
|
-
parser = argparse.ArgumentParser(description="Start the UTIM Production Server")
|
|
23
|
-
parser.add_argument("--host", default="0.0.0.0")
|
|
24
|
-
parser.add_argument("--port", type=int, default=int(os.environ.get("PORT", 8000)))
|
|
25
|
-
parser.add_argument("--reload", action="store_true")
|
|
26
|
-
parser.add_argument("--workers", type=int, default=1)
|
|
27
|
-
args = parser.parse_args()
|
|
28
|
-
|
|
29
|
-
required = {
|
|
30
|
-
"DATABASE_URL": os.environ.get("DATABASE_URL"),
|
|
31
|
-
"OPENROUTER_API_KEY": os.environ.get("OPENROUTER_API_KEY"),
|
|
32
|
-
"UTIM_MASTER_KEY": os.environ.get("UTIM_MASTER_KEY"),
|
|
33
|
-
}
|
|
34
|
-
missing = [k for k, v in required.items() if not v]
|
|
35
|
-
if missing:
|
|
36
|
-
print(f"[ERROR] Missing required env vars: {', '.join(missing)}")
|
|
37
|
-
print(" Set these in Railway → Service → Variables")
|
|
38
|
-
sys.exit(1)
|
|
39
|
-
|
|
40
|
-
print(f"🚀 UTIM Production Server")
|
|
41
|
-
print(f" http://{args.host}:{args.port}")
|
|
42
|
-
print(f" Docs: http://{args.host}:{args.port}/docs")
|
|
43
|
-
|
|
44
|
-
uvicorn.run(
|
|
45
|
-
"utim_cli.server.router:app",
|
|
46
|
-
host=args.host,
|
|
47
|
-
port=args.port,
|
|
48
|
-
reload=args.reload,
|
|
49
|
-
workers=args.workers if not args.reload else 1,
|
|
50
|
-
log_config=None, # we handle logging ourselves
|
|
51
|
-
access_log=False, # our middleware does structured access logs
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if __name__ == "__main__":
|
|
56
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|