AQIT
0.1.0
Toggle main menu visibility
Loading...
Searching...
No Matches
setup_cli.py
Go to the documentation of this file.
1
# Copyright (c) 2025-present Aquin Labs Private Limited. All Rights Reserved.
2
# This file is part of the Aquin Engine. Unauthorized copying, modification,
3
# distribution, or use of this file, via any medium, is strictly prohibited.
4
# Proprietary and confidential. See LICENSE for terms.
5
6
"""aquin setup machine — prepare this host as a (remote) compute box for desktop/CLI."""
7
8
from
__future__
import
annotations
9
10
import
json
11
import
os
12
import
platform
13
import
socket
14
import
subprocess
15
import
sys
16
import
time
17
from
datetime
import
datetime, timezone
18
from
pathlib
import
Path
19
from
typing
import
Any
20
21
22
def
_utc_now
() -> str:
23
return
datetime.now(timezone.utc).strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
24
25
26
def
_gpu_summary
() -> dict[str, Any]:
27
out: dict[str, Any] = {
"accelerator"
:
"cpu"
,
"detail"
:
None
}
28
try
:
29
import
torch
30
31
if
torch.cuda.is_available():
32
out[
"accelerator"
] =
"cuda"
33
out[
"detail"
] = torch.cuda.get_device_name(0)
34
out[
"device_count"
] = torch.cuda.device_count()
35
elif
getattr(torch.backends,
"mps"
,
None
)
and
torch.backends.mps.is_available():
36
out[
"accelerator"
] =
"mps"
37
out[
"detail"
] =
"Apple Metal"
38
else
:
39
out[
"accelerator"
] =
"cpu"
40
out[
"detail"
] =
"torch installed, no CUDA/MPS"
41
out[
"torch"
] = getattr(torch,
"__version__"
,
"?"
)
42
except
Exception
as
exc:
43
out[
"accelerator"
] =
"unknown"
44
out[
"detail"
] = f
"torch unavailable: {exc}"
45
return
out
46
47
48
def
_sshd_listening
() -> dict[str, Any]:
49
"""Best-effort: is something listening on port 22? (OpenSSH usually)."""
50
result: dict[str, Any] = {
"port_22_open"
:
None
,
"notes"
: []}
51
try
:
52
with
socket.create_connection((
"127.0.0.1"
, 22), timeout=0.4):
53
result[
"port_22_open"
] =
True
54
except
OSError:
55
result[
"port_22_open"
] =
False
56
result[
"notes"
].append(
57
"Nothing on localhost:22 — install/start OpenSSH (sshd) if this box should accept SSH."
58
)
59
60
# Optional service name hints
61
for
cmd
in
(
62
[
"systemctl"
,
"is-active"
,
"ssh"
],
63
[
"systemctl"
,
"is-active"
,
"sshd"
],
64
[
"service"
,
"ssh"
,
"status"
],
65
):
66
try
:
67
r = subprocess.run(
68
cmd,
69
capture_output=
True
,
70
text=
True
,
71
timeout=2,
72
)
73
text = (r.stdout
or
r.stderr
or
""
).strip().lower()
74
if
"active"
in
text
or
r.returncode == 0:
75
result[
"service_hint"
] =
" "
.join(cmd)
76
break
77
except
Exception:
78
continue
79
return
result
80
81
82
def
_local_ips
() -> list[str]:
83
ips: list[str] = []
84
try
:
85
hostname = socket.gethostname()
86
for
info
in
socket.getaddrinfo(hostname,
None
):
87
ip = info[4][0]
88
if
ip
and
ip
not
in
ips
and
not
ip.startswith(
"127."
):
89
ips.append(ip)
90
except
Exception:
91
pass
92
return
ips[:8]
93
94
95
def
_ensure_aquin_home
() -> Path:
96
home = Path(os.environ.get(
"AQUIN_HOME"
)
or
(Path.home() /
".aquin"
))
97
home.mkdir(parents=
True
, exist_ok=
True
)
98
return
home
99
100
101
def
_start_daemon
(port: int, wait_s: float = 40.0) -> dict[str, Any]:
102
from
aquin.engine
import
model_daemon
103
from
aquin.engine.engine_info
import
resolve_engine_port
104
105
if
port:
106
os.environ[
"AQUIN_ENGINE_PORT"
] = str(port)
107
effective = port
or
resolve_engine_port()
108
already = model_daemon.is_running()
109
if
already:
110
h = model_daemon.health()
or
{}
111
return
{
112
"ok"
:
True
,
113
"already"
:
True
,
114
"port"
: effective,
115
"health"
: h,
116
}
117
ok = model_daemon.ensure_running(wait_seconds=wait_s)
118
h = model_daemon.health()
if
ok
else
None
119
return
{
120
"ok"
: bool(ok),
121
"already"
:
False
,
122
"port"
: effective,
123
"health"
: h
or
{},
124
"error"
:
None
if
ok
else
"daemon did not become healthy (see ~/.aquin/daemon.log)"
,
125
}
126
127
128
def
_write_machine_record
(payload: dict[str, Any]) -> Path:
129
home =
_ensure_aquin_home
()
130
path = home /
"machine-setup.json"
131
path.write_text(json.dumps(payload, indent=2) +
"\n"
, encoding=
"utf-8"
)
132
return
path
133
134
135
def
_tunnel_block
(port: int, user: str, host: str) -> str:
136
target = f
"{user}@{host}"
if
user
and
host
else
"USER@HOST"
137
return
"\n"
.join(
138
[
139
"# ── Desktop / laptop connection ─────────────────────────────────"
,
140
"# On your laptop (keep tunnel open):"
,
141
f
"ssh -N -L {port}:127.0.0.1:{port} {target}"
,
142
"# or from monorepo:"
,
143
f
"./ide/app/scripts/ssh-engine-tunnel.sh {target}"
,
144
""
,
145
"# Then start Aquin desktop with remote engine:"
,
146
f
"export AQUIN_ENGINE_REMOTE=1"
,
147
f
"export AQUIN_ENGINE_HOST=127.0.0.1"
,
148
f
"export AQUIN_ENGINE_PORT={port}"
,
149
"cd ide/app && npm start"
,
150
""
,
151
"# Engine stays on *this* machine (127.0.0.1 only). Tunnel makes it look local."
,
152
"# Optional: aquin load model <id> here to put a model in VRAM."
,
153
]
154
)
155
156
157
def
cmd_setup
(args: list[str]) ->
None
:
158
"""
159
aquin setup machine — prepare this host for local or remote (desktop tunnel) compute.
160
"""
161
if
not
args
or
args[0]
in
(
"--help"
,
"-h"
,
"help"
):
162
print(
"Usage: aquin setup machine [options]"
)
163
print(
""
)
164
print(
" Probe GPU + SSH readiness, ensure ~/.aquin, start the model daemon"
)
165
print(
" (localhost only), and print SSH tunnel + desktop env for remote GPU."
)
166
print(
""
)
167
print(
"Options:"
)
168
print(
" --port N Daemon port (default: 17832 / AQUIN_ENGINE_PORT)"
)
169
print(
" --no-daemon Do not start the model daemon"
)
170
print(
" --check Report only (no write / no start)"
)
171
print(
" --json Machine-readable summary on stdout"
)
172
print(
" --ssh-user U Hint for tunnel command (default: $USER)"
)
173
print(
" --ssh-host H Hint for tunnel command (default: hostname)"
)
174
return
175
176
if
args[0] !=
"machine"
:
177
print(f
"Unknown setup target: {args[0]}"
)
178
print(
"Usage: aquin setup machine"
)
179
sys.exit(1)
180
181
rest = args[1:]
182
port = 0
183
no_daemon =
False
184
check_only =
False
185
as_json =
False
186
ssh_user = (os.environ.get(
"USER"
)
or
os.environ.get(
"LOGNAME"
)
or
""
).strip()
or
"user"
187
ssh_host = socket.gethostname()
188
189
i = 0
190
while
i < len(rest):
191
a = rest[i]
192
if
a
in
(
"--help"
,
"-h"
,
"help"
):
193
cmd_setup
([])
194
return
195
if
a ==
"--port"
and
i + 1 < len(rest):
196
port = int(rest[i + 1])
197
i += 2
198
continue
199
if
a.startswith(
"--port="
):
200
port = int(a.split(
"="
, 1)[1])
201
i += 1
202
continue
203
if
a ==
"--no-daemon"
:
204
no_daemon =
True
205
i += 1
206
continue
207
if
a ==
"--check"
:
208
check_only =
True
209
i += 1
210
continue
211
if
a ==
"--json"
:
212
as_json =
True
213
i += 1
214
continue
215
if
a ==
"--ssh-user"
and
i + 1 < len(rest):
216
ssh_user = rest[i + 1]
217
i += 2
218
continue
219
if
a ==
"--ssh-host"
and
i + 1 < len(rest):
220
ssh_host = rest[i + 1]
221
i += 2
222
continue
223
print(f
"Unknown flag: {a}"
, file=sys.stderr)
224
sys.exit(1)
225
226
from
aquin.engine.engine_info
import
DEFAULT_ENGINE_PORT, resolve_engine_port
227
228
if
not
port:
229
port = resolve_engine_port()
or
DEFAULT_ENGINE_PORT
230
231
summary: dict[str, Any] = {
232
"command"
:
"setup machine"
,
233
"check_only"
: check_only,
234
"when"
:
_utc_now
(),
235
"hostname"
: socket.gethostname(),
236
"platform"
: {
237
"system"
: platform.system(),
238
"release"
: platform.release(),
239
"machine"
: platform.machine(),
240
"python"
: sys.version.split()[0],
241
"executable"
: sys.executable,
242
},
243
"gpu"
:
_gpu_summary
(),
244
"ssh"
:
_sshd_listening
(),
245
"network"
: {
"local_ips"
:
_local_ips
()},
246
"port"
: port,
247
"daemon"
:
None
,
248
"ok"
:
True
,
249
"next"
: {},
250
}
251
252
try
:
253
import
aquin
# noqa: F401
254
255
summary[
"aquin_import"
] =
"ok"
256
except
Exception
as
exc:
257
summary[
"aquin_import"
] = f
"failed: {exc}"
258
summary[
"ok"
] =
False
259
260
if
not
no_daemon
and
not
check_only
and
summary.get(
"aquin_import"
) ==
"ok"
:
261
daemon_info =
_start_daemon
(port)
262
summary[
"daemon"
] = daemon_info
263
if
not
daemon_info.get(
"ok"
):
264
summary[
"ok"
] =
False
265
elif
not
no_daemon:
266
# check path: probe only
267
try
:
268
from
aquin.engine
import
model_daemon
269
270
h = model_daemon.health()
271
summary[
"daemon"
] = {
272
"ok"
: h
is
not
None
,
273
"already"
: h
is
not
None
,
274
"port"
: port,
275
"health"
: h
or
{},
276
}
277
except
Exception
as
exc:
278
summary[
"daemon"
] = {
"ok"
:
False
,
"error"
: str(exc),
"port"
: port}
279
280
tunnel =
_tunnel_block
(port, ssh_user, ssh_host)
281
summary[
"next"
] = {
282
"ssh_target"
: f
"{ssh_user}@{ssh_host}"
,
283
"tunnel"
: f
"ssh -N -L {port}:127.0.0.1:{port} {ssh_user}@{ssh_host}"
,
284
"desktop_env"
: {
285
"AQUIN_ENGINE_REMOTE"
:
"1"
,
286
"AQUIN_ENGINE_HOST"
:
"127.0.0.1"
,
287
"AQUIN_ENGINE_PORT"
: str(port),
288
},
289
"load_model"
:
"aquin load model <id>"
,
290
}
291
292
if
not
check_only:
293
try
:
294
path =
_write_machine_record
(
295
{
296
"setup_at"
: summary[
"when"
],
297
"hostname"
: summary[
"hostname"
],
298
"port"
: port,
299
"ssh_target"
: summary[
"next"
][
"ssh_target"
],
300
"gpu"
: summary[
"gpu"
],
301
"daemon_ok"
: (summary.get(
"daemon"
)
or
{}).get(
"ok"
),
302
}
303
)
304
summary[
"wrote"
] = str(path)
305
except
Exception
as
exc:
306
summary[
"wrote_error"
] = str(exc)
307
308
if
as_json:
309
print(json.dumps(summary, indent=2, ensure_ascii=
False
))
310
sys.exit(0
if
summary.get(
"ok"
)
else
1)
311
312
# Human output — agent-friendly, greppable markers
313
print(
"[setup machine] host probes"
)
314
print(f
" hostname : {summary['hostname']}"
)
315
print(f
" platform : {summary['platform']['system']} {summary['platform']['machine']}"
)
316
print(f
" python : {summary['platform']['python']} ({summary['platform']['executable']})"
)
317
print(f
" aquin : {summary.get('aquin_import')}"
)
318
gpu = summary[
"gpu"
]
319
print(f
" accelerator: {gpu.get('accelerator')} {gpu.get('detail') or ''}"
.rstrip())
320
ssh = summary[
"ssh"
]
321
print(
322
f
" ssh :22 : "
323
f
"{'open' if ssh.get('port_22_open') else 'closed/unavailable' if ssh.get('port_22_open') is False else 'unknown'}"
324
)
325
for
n
in
ssh.get(
"notes"
)
or
[]:
326
print(f
" note: {n}"
)
327
328
d = summary.get(
"daemon"
)
or
{}
329
if
no_daemon:
330
print(
"[setup machine] daemon: skipped (--no-daemon)"
)
331
elif
check_only:
332
print(f
"[setup machine] daemon check: ok={d.get('ok')} port={d.get('port', port)}"
)
333
else
:
334
if
d.get(
"ok"
):
335
state =
"already running"
if
d.get(
"already"
)
else
"started"
336
print(f
"[setup machine] daemon: {state} on 127.0.0.1:{d.get('port', port)}"
)
337
h = d.get(
"health"
)
or
{}
338
if
h.get(
"model_id"
):
339
print(f
" model_id : {h.get('model_id')}"
)
340
else
:
341
print(f
"[setup machine] daemon: FAILED — {d.get('error') or 'unknown'}"
, file=sys.stderr)
342
343
if
summary.get(
"wrote"
):
344
print(f
"[setup machine] wrote {summary['wrote']}"
)
345
346
print(
""
)
347
print(tunnel)
348
print(
""
)
349
if
summary.get(
"ok"
):
350
print(
"[setup machine] OK — engine ready for SSH tunnel from your laptop."
)
351
else
:
352
print(
"[setup machine] completed with issues (see above)."
, file=sys.stderr)
353
sys.exit(1)
aquin.engine.engine_info
Definition
engine_info.py:1
aquin.engine
Definition
__init__.py:1
aquin.setup_cli._utc_now
str _utc_now()
Definition
setup_cli.py:26
aquin.setup_cli._write_machine_record
Path _write_machine_record(dict[str, Any] payload)
Definition
setup_cli.py:132
aquin.setup_cli.cmd_setup
None cmd_setup(list[str] args)
Definition
setup_cli.py:161
aquin.setup_cli._sshd_listening
dict[str, Any] _sshd_listening()
Definition
setup_cli.py:52
aquin.setup_cli._gpu_summary
dict[str, Any] _gpu_summary()
Definition
setup_cli.py:30
aquin.setup_cli._start_daemon
dict[str, Any] _start_daemon(int port, float wait_s=40.0)
Definition
setup_cli.py:105
aquin.setup_cli._local_ips
list[str] _local_ips()
Definition
setup_cli.py:86
aquin.setup_cli._tunnel_block
str _tunnel_block(int port, str user, str host)
Definition
setup_cli.py:139
aquin.setup_cli._ensure_aquin_home
Path _ensure_aquin_home()
Definition
setup_cli.py:99
aquin
setup_cli.py
AQIT · Aquin Labs Private Limited · Apache 2.0 · Generated by
1.18.0