3232# Path discovery
3333# ============================================================
3434
35- def get_ark_root () -> Path :
36- """Find the ARK installation root (where projects/ lives)."""
37- # Editable install: relative to this file
38- pkg_root = Path (__file__ ).parent .parent .absolute ()
39- if (pkg_root / "projects" ).exists ():
40- return pkg_root
41- # First run: create projects/ dir
42- if (pkg_root / "pyproject.toml" ).exists ():
43- (pkg_root / "projects" ).mkdir (exist_ok = True )
44- return pkg_root
45- # Fallback: ~/.ark/
46- home_ark = Path .home () / ".ark"
47- home_ark .mkdir (exist_ok = True )
48- (home_ark / "projects" ).mkdir (exist_ok = True )
49- return home_ark
35+ from ark .paths import get_ark_root , get_config_dir
5036
5137
5238def get_projects_dir () -> Path :
53- return get_ark_root () / "projects"
39+ root = get_ark_root ()
40+ pdir = root / "projects"
41+ pdir .mkdir (exist_ok = True )
42+ return pdir
5443
5544
5645def get_project_config (name : str ) -> dict :
@@ -1900,8 +1889,8 @@ def cmd_status(args):
19001889 for name in stopped_projects :
19011890 _show_project_status_brief (name )
19021891
1903- _webapp_db = Path . home () / ". ark_webapp.db"
1904- _disabled_flag = Path . home () / ".ark_webapp_disabled "
1892+ _webapp_db = get_ark_root () / "ark_webapp" / "webapp .db"
1893+ _disabled_flag = get_ark_root () / "ark_webapp" / "disabled "
19051894 if _webapp_db .exists ():
19061895 import sqlite3 as _sq
19071896 try :
@@ -2893,38 +2882,6 @@ class RunArgs:
28932882 cmd_run (RunArgs ())
28942883
28952884
2896- # ============================================================
2897- # ark dashboard
2898- # ============================================================
2899-
2900- def cmd_dashboard (args ):
2901- """Start the web dashboard for monitoring projects."""
2902- try :
2903- import uvicorn
2904- from ark .dashboard import create_app
2905- except ImportError :
2906- print (f"{ _c ('Error:' , Colors .RED )} Dashboard dependencies not installed." )
2907- print (f" Install with: { _c ('pip install ark-research[dashboard]' , Colors .BOLD )} " )
2908- print (f" Or: { _c ('pip install fastapi uvicorn[standard]' , Colors .BOLD )} " )
2909- sys .exit (1 )
2910-
2911- host , port = args .host , args .port
2912-
2913- if args .daemon :
2914- pid = os .fork ()
2915- if pid > 0 :
2916- print (f"Dashboard started in background (PID { pid } )" )
2917- print (f" { _c (f'http://{ host } :{ port } ' , Colors .CYAN )} " )
2918- return
2919- # Child process
2920- os .setsid ()
2921- sys .stdin .close ()
2922-
2923- print (f"\n { _c ('ARK Dashboard' , Colors .BOLD )} — http://{ host } :{ port } \n " )
2924- app = create_app ()
2925- uvicorn .run (app , host = host , port = port , log_level = "warning" )
2926-
2927-
29282885# ============================================================
29292886# ark webapp
29302887# ============================================================
@@ -2942,7 +2899,7 @@ def cmd_webapp(args):
29422899 try :
29432900 import uvicorn
29442901 from ark .webapp import create_app
2945- from ark .webapp .config import get_settings , _ENV_FILE
2902+ from ark .webapp .config import get_settings , _env_file
29462903 except ImportError :
29472904 print (f"{ _c ('Error:' , Colors .RED )} Webapp dependencies not installed." )
29482905 print (f" Install with: { _c ('pip install ark-research[webapp]' , Colors .BOLD )} " )
@@ -2955,23 +2912,28 @@ def cmd_webapp(args):
29552912 settings = get_settings ()
29562913 if not (settings .smtp_user and settings .smtp_password ):
29572914 print (f"\n { _c ('Warning:' , Colors .YELLOW )} SMTP not configured — magic link emails won't be sent." )
2958- print (f" Edit { _c (str (_ENV_FILE ), Colors .CYAN )} and set SMTP_USER / SMTP_PASSWORD.\n " )
2915+ print (f" Edit { _c (str (_env_file () ), Colors .CYAN )} and set SMTP_USER / SMTP_PASSWORD.\n " )
29592916
29602917 if args .daemon :
2961- pid_file = Path .home () / ".ark_webapp.pid"
2962- log_file = Path .home () / ".ark_webapp.log"
2918+ _root = get_ark_root ()
2919+ _webapp_dir = _root / "ark_webapp"
2920+ _webapp_dir .mkdir (exist_ok = True )
2921+ pid_file = _webapp_dir / "webapp.pid"
2922+ log_file = _webapp_dir / "webapp.log"
29632923 pid = os .fork ()
29642924 if pid > 0 :
29652925 pid_file .write_text (str (pid ))
29662926 print (f" { _c ('ARK Webapp' , Colors .BOLD )} started in background (PID { pid } )" )
29672927 print (f" URL: { _c (f'http://{ host } :{ port } ' , Colors .CYAN )} " )
29682928 print (f" Log: { _c (str (log_file ), Colors .DIM )} " )
29692929 return
2970- # Child process
2930+ # Child process — detach and redirect file descriptors
29712931 os .setsid ()
2972- with open (log_file , "a" ) as lf :
2973- sys .stdout = lf
2974- sys .stderr = lf
2932+ sys .stdin .close ()
2933+ fd = os .open (str (log_file ), os .O_WRONLY | os .O_CREAT | os .O_APPEND , 0o644 )
2934+ os .dup2 (fd , 1 ) # stdout
2935+ os .dup2 (fd , 2 ) # stderr
2936+ os .close (fd )
29752937
29762938 print (f"\n { _c ('ARK Research Portal' , Colors .BOLD )} — http://{ host } :{ port } \n " )
29772939 app = create_app ()
@@ -2991,8 +2953,8 @@ def cmd_web(args):
29912953 subcmd = args .web_cmd
29922954 project_filter = getattr (args , 'project' , None ) or None
29932955
2994- _DISABLED_FLAG = Path . home () / ".ark_webapp_disabled "
2995- _DB = Path . home () / ". ark_webapp.db"
2956+ _DISABLED_FLAG = get_ark_root () / "ark_webapp" / "disabled "
2957+ _DB = get_ark_root () / "ark_webapp" / "webapp .db"
29962958
29972959 if not _DB .exists ():
29982960 print (f"{ _c ('Error:' , Colors .RED )} No webapp DB found. Start the webapp first." )
@@ -3434,19 +3396,12 @@ def main():
34343396 p_restart .add_argument ("project" , help = "Project name" )
34353397 p_restart .set_defaults (func = cmd_restart )
34363398
3437- # ark dashboard
3438- p_dash = subparsers .add_parser ("dashboard" , help = "Start web dashboard for monitoring projects" )
3439- p_dash .add_argument ("--port" , type = int , default = 8420 , help = "Port (default: 8420)" )
3440- p_dash .add_argument ("--host" , default = "0.0.0.0" , help = "Host (default: 0.0.0.0)" )
3441- p_dash .add_argument ("--daemon" , action = "store_true" , help = "Run in background" )
3442- p_dash .set_defaults (func = cmd_dashboard )
3443-
34443399 # ark webapp
34453400 p_webapp = subparsers .add_parser ("webapp" , help = "Start or manage lab-facing research portal" )
34463401 webapp_sub = p_webapp .add_subparsers (dest = "webapp_cmd" )
34473402 webapp_sub .add_parser ("disable" , help = "Block new project submissions" )
34483403 webapp_sub .add_parser ("enable" , help = "Allow new project submissions" )
3449- p_webapp .add_argument ("--port" , type = int , default = 8422 , help = "Port (default: 8422 )" )
3404+ p_webapp .add_argument ("--port" , type = int , default = 8423 , help = "Port (default: 8423 )" )
34503405 p_webapp .add_argument ("--host" , default = "0.0.0.0" , help = "Host (default: 0.0.0.0)" )
34513406 p_webapp .add_argument ("--daemon" , action = "store_true" , help = "Run in background" )
34523407 p_webapp .set_defaults (func = cmd_webapp )
0 commit comments