@orb44/cli 0.1.11 → 0.1.12

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.
package/README.md CHANGED
@@ -13,11 +13,11 @@ npx @orb44/cli login --url https://orb44.com
13
13
  Open the printed link in a browser where you are already signed in, confirm the domain, then optionally install the systemd daemon (default no). After a global install the command is `orb44`.
14
14
 
15
15
  ```bash
16
- npx @orb44/cli@0.1.11 status
17
- npx @orb44/cli@0.1.11 pulse
18
- npx @orb44/cli@0.1.11 install # later: background pulse, starts after reboot
16
+ npx @orb44/cli@0.1.12 status
17
+ npx @orb44/cli@0.1.12 pulse
18
+ npx @orb44/cli@0.1.12 install # asks daemon (default yes) and logs (default no)
19
19
  orb44 update # after install: replace /usr/lib/orb44-sat from npm
20
- npx @orb44/cli@0.1.11 logout
20
+ npx @orb44/cli@0.1.12 logout
21
21
  ```
22
22
 
23
23
  Do not run bare `npx @orb44/cli` — it can reuse an old cache. Pin the version or use `orb44` after install.
package/bin/orb44.mjs CHANGED
@@ -27,6 +27,7 @@ function args() {
27
27
  else if (a === "--logs") out.logs = true;
28
28
  else if (a === "--force") out.force = true;
29
29
  else if (a === "--purge") out.purge = true;
30
+ else if (a === "--version" || a === "-V" || a === "-v") out.version = true;
30
31
  else if (a === "--url" || a === "--code" || a === "--name" || a === "--interval" || a === "--lang") {
31
32
  out[a.slice(2)] = argv[++i];
32
33
  } else if (!a.startsWith("-")) out._.push(a);
@@ -105,8 +106,43 @@ function quote(p) {
105
106
  return /[\s"$]/.test(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
106
107
  }
107
108
 
109
+ function localCliVersion() {
110
+ const ver = readCliVersion(SCRIPT);
111
+ return ver && ver !== "0.0.0" ? ver : "—";
112
+ }
113
+
114
+ async function latestCliVersion() {
115
+ try {
116
+ const ac = new AbortController();
117
+ const timer = setTimeout(() => ac.abort(), 4000);
118
+ const meta = await fetchLatestMeta((url, init) => fetch(url, { ...init, signal: ac.signal }));
119
+ clearTimeout(timer);
120
+ return meta.version;
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+
126
+ function printVersions(current, latest) {
127
+ const here = current && current !== "0.0.0" ? current : localCliVersion();
128
+ console.log(dim(`${t(lang, "ver_here")}: ${here}`));
129
+ if (!latest) {
130
+ console.log(dim(`${t(lang, "ver_latest")}: ${t(lang, "ver_unknown")}`));
131
+ return false;
132
+ }
133
+ const behind = here !== "—" && cmpVer(here, latest) < 0;
134
+ const same = here !== "—" && cmpVer(here, latest) === 0;
135
+ console.log(dim(`${t(lang, "ver_latest")}: ${latest}${same ? " " + t(lang, "ver_ok") : ""}`));
136
+ if (behind) console.log(dim(t(lang, "ver_behind", { ver: latest })));
137
+ return behind;
138
+ }
139
+
140
+ async function printVersionPair() {
141
+ return printVersions(localCliVersion(), await latestCliVersion());
142
+ }
143
+
108
144
  function banner() {
109
- console.log(`\n🛰️ ${bold(t(lang, "banner_title"))}`);
145
+ console.log(`\n🛰️ ${bold(t(lang, "banner_title"))} ${dim(localCliVersion())}`);
110
146
  console.log(dim(`${t(lang, "banner_sub")}\n`));
111
147
  }
112
148
 
@@ -142,14 +178,14 @@ async function ensureLang(opts) {
142
178
  return lang;
143
179
  }
144
180
 
145
- async function wantDaemon(opts) {
181
+ async function wantDaemon(opts, { ifYes = false, index = 0 } = {}) {
146
182
  if (opts.daemon) return true;
147
- if (opts.yes) return false;
148
- if (!input.isTTY || !output.isTTY) return false;
183
+ if (opts.yes) return ifYes;
184
+ if (!input.isTTY || !output.isTTY) return ifYes;
149
185
  const idx = await pickFromList({
150
186
  title: t(lang, "ask_daemon"),
151
187
  items: [t(lang, "daemon_no"), t(lang, "daemon_yes")],
152
- index: 0,
188
+ index,
153
189
  hint: "↑↓ Enter",
154
190
  stdin: input,
155
191
  stdout: output,
@@ -346,8 +382,9 @@ async function cmdLogin(opts) {
346
382
 
347
383
  const daemon = await wantDaemon(opts);
348
384
  const logs = await wantLogs(opts);
349
- applyGrants(device, { daemon, logs });
350
- saveDevice(device);
385
+ const grants = applyGrants(device, { daemon, logs });
386
+ persistDevice(device, [SYSTEM_DEVICE]);
387
+ printGrants(grants);
351
388
  if (logs) console.log(dim(t(lang, "logs_on")));
352
389
  else console.log(dim(t(lang, "logs_skip")));
353
390
 
@@ -359,9 +396,8 @@ async function cmdLogin(opts) {
359
396
  console.log("\n📡 " + t(lang, "pulse_ok"));
360
397
  printAdvice(out.body?.notes);
361
398
  if (daemon) {
362
- if (cmdInstall(opts, { enable: true })) {
363
- console.log("\n" + t(lang, "login_done"));
364
- }
399
+ const installed = await cmdInstall({ ...opts, daemon: true, logs }, { enable: true, skipAsk: true });
400
+ if (installed) console.log("\n" + t(lang, "login_done"));
365
401
  } else {
366
402
  console.log(dim("\n" + t(lang, "daemon_skip")));
367
403
  }
@@ -402,6 +438,8 @@ async function cmdDaemon(opts) {
402
438
  const tick = async () => {
403
439
  const hh = new Date().toISOString().slice(11, 19);
404
440
  try {
441
+ const fresh = loadDevice();
442
+ if (fresh?.secret) Object.assign(device, fresh);
405
443
  const { out, pulse } = await sendPulse(device, { preview: false });
406
444
  if (!out.ok) {
407
445
  console.error(`⚠️ ${hh} ${apiFailText(lang, out, t)}`);
@@ -544,8 +582,30 @@ function tryEnable(asSystem) {
544
582
  return { ok: false, err: (st.stdout || st.stderr || "not active").trim().slice(0, 240) };
545
583
  }
546
584
 
547
- function cmdInstall(opts, { enable = false } = {}) {
585
+ function persistDevice(device, extraPaths = []) {
586
+ saveDevice(device);
587
+ const body = JSON.stringify(device, null, 2);
588
+ for (const p of extraPaths) {
589
+ if (!p || path.resolve(p) === path.resolve(DEVICE_FILE)) continue;
590
+ try {
591
+ fs.writeFileSync(p, body, { mode: 0o600 });
592
+ } catch {
593
+ /* other key unreadable */
594
+ }
595
+ }
596
+ }
597
+
598
+ function printGrants(grants) {
599
+ const on = t(lang, "grant_on");
600
+ const off = t(lang, "grant_off");
601
+ console.log(dim(t(lang, "grant_process") + ": " + on));
602
+ console.log(dim(t(lang, "grant_daemon") + ": " + (grants.daemon ? on : off)));
603
+ console.log(dim(t(lang, "grant_logs") + ": " + (grants.logs ? on : off)));
604
+ }
605
+
606
+ async function cmdInstall(opts, { enable = false, skipAsk = false } = {}) {
548
607
  applyLang(opts);
608
+ if (!skipAsk) await printVersionPair();
549
609
  const rec = loadDeviceRecord();
550
610
  if (!rec?.secret) {
551
611
  console.error("⚠️ " + t(lang, "need_login"));
@@ -554,15 +614,20 @@ function cmdInstall(opts, { enable = false } = {}) {
554
614
  const srcPath = rec.path || DEVICE_FILE;
555
615
  const device = stripDevicePath(rec);
556
616
  if (opts.url) device.api = String(opts.url).replace(/\/$/, "");
557
- applyGrants(device, { daemon: true, logs: opts.logs ? true : device.grants?.logs });
558
- saveDevice(device);
559
- if (srcPath !== DEVICE_FILE) {
560
- try {
561
- fs.writeFileSync(srcPath, JSON.stringify(device, null, 2), { mode: 0o600 });
562
- } catch {
563
- /* unreadable system key stays as-is */
564
- }
617
+ let daemon;
618
+ let logs;
619
+ if (skipAsk) {
620
+ daemon = opts.daemon != null ? Boolean(opts.daemon) : Boolean(device.grants?.daemon);
621
+ logs = opts.logs != null ? Boolean(opts.logs) : Boolean(device.grants?.logs);
622
+ } else {
623
+ daemon = await wantDaemon(opts, { ifYes: true, index: 1 });
624
+ logs = await wantLogs(opts);
565
625
  }
626
+ const grants = applyGrants(device, { daemon, logs });
627
+ persistDevice(device, [srcPath, SYSTEM_DEVICE]);
628
+ printGrants(grants);
629
+ if (logs) console.log(dim(t(lang, "logs_on")));
630
+ else console.log(dim(t(lang, "logs_skip")));
566
631
  const asSystem = Boolean(opts.system) || process.getuid?.() === 0;
567
632
  const interval = intervalSec(opts.interval);
568
633
  let deviceFile = DEVICE_FILE;
@@ -574,6 +639,12 @@ function cmdInstall(opts, { enable = false } = {}) {
574
639
  deviceFile = acct.deviceFile;
575
640
  user = acct.user;
576
641
  script = acct.script;
642
+ persistDevice(device, [SYSTEM_DEVICE]);
643
+ try {
644
+ spawnSync("chown", ["orb44:orb44", SYSTEM_DEVICE], { encoding: "utf8" });
645
+ } catch {
646
+ /* key stays root-owned until next chown -R */
647
+ }
577
648
  console.log(dim(t(lang, "daemon_user", { user, file: deviceFile })));
578
649
  } else {
579
650
  console.log(dim(t(lang, "daemon_user_fail", { err: acct.err ? `: ${acct.err}` : "" })));
@@ -600,13 +671,24 @@ function cmdInstall(opts, { enable = false } = {}) {
600
671
  /* /usr/local/bin missing */
601
672
  }
602
673
  }
603
- if (enable) {
674
+ if (enable && daemon) {
604
675
  const on = tryEnable(asSystem);
605
676
  if (on.ok) {
677
+ spawnSync("systemctl", asSystem ? ["try-restart", "orb44-satellite"] : ["--user", "try-restart", "orb44-satellite"], {
678
+ encoding: "utf8",
679
+ });
606
680
  console.log("✅ " + t(lang, "daemon_on"));
681
+ try {
682
+ await sendPulse(device, { preview: false });
683
+ } catch {
684
+ /* next daemon tick */
685
+ }
607
686
  return true;
608
687
  }
609
688
  console.log("⚠️ " + t(lang, "unit_enable_fail", { err: on.err ? `: ${on.err}` : "" }));
689
+ } else if (!daemon) {
690
+ console.log(dim(t(lang, "daemon_skip")));
691
+ return false;
610
692
  }
611
693
  if (asSystem) {
612
694
  console.log(dim(" " + t(lang, "install_root")));
@@ -683,9 +765,11 @@ async function cmdUpdate() {
683
765
  try {
684
766
  meta = await fetchLatestMeta();
685
767
  } catch (e) {
768
+ printVersions(current, null);
686
769
  console.error("⚠️ " + t(lang, "update_fail", { err: `: ${String(e.message || e).slice(0, 160)}` }));
687
770
  process.exit(1);
688
771
  }
772
+ printVersions(current, meta.version);
689
773
  const pin = t(lang, "update_npx", { version: meta.version });
690
774
  const roots = pickSatRoots(SCRIPT);
691
775
  const stale = staleSatRoots(roots, meta.version, { force: Boolean(opts.force) });
@@ -733,10 +817,16 @@ async function cmdUpdate() {
733
817
  console.log(dim(pin));
734
818
  }
735
819
 
736
- function cmdStatus() {
820
+ async function cmdVersion() {
821
+ applyLang(opts);
822
+ await printVersionPair();
823
+ }
824
+
825
+ async function cmdStatus() {
737
826
  applyLang(opts);
738
827
  const device = loadDevice();
739
828
  banner();
829
+ await printVersionPair();
740
830
  if (!device) {
741
831
  console.log("⚠️ " + t(lang, "not_paired"));
742
832
  return;
@@ -789,11 +879,11 @@ async function cmdLang(flags) {
789
879
 
790
880
  function help() {
791
881
  applyLang(opts);
792
- console.log(t(lang, "help", { file: DEVICE_FILE }));
882
+ console.log(t(lang, "help", { file: DEVICE_FILE, version: localCliVersion() }));
793
883
  }
794
884
 
795
885
  const opts = args();
796
- const cmd = opts._[0] || "help";
886
+ const cmd = opts.version ? "version" : opts._[0] || "help";
797
887
  const run = {
798
888
  login: () => cmdLogin(opts),
799
889
  pulse: cmdPulse,
@@ -802,6 +892,7 @@ const run = {
802
892
  uninstall: () => cmdUninstall(opts),
803
893
  status: cmdStatus,
804
894
  update: cmdUpdate,
895
+ version: cmdVersion,
805
896
  logout: cmdLogout,
806
897
  lang: () => cmdLang(opts),
807
898
  help,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orb44/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Orb44: street snapshot of your site. This CLI is the Watch satellite — pulse from the host (load, listeners, hardening). The cabinet does not run commands on the machine.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -49,6 +49,11 @@ const STR = {
49
49
  logs_yes: "Yes — last errors if readable",
50
50
  logs_skip: "Log monitoring off. Later: orb44 login --logs or orb44 install --logs",
51
51
  logs_on: "Log monitoring on. Docker/kube/nginx only if this user can read them.",
52
+ grant_process: "System processes",
53
+ grant_daemon: "Restart after reboot",
54
+ grant_logs: "Log monitoring",
55
+ grant_on: "on",
56
+ grant_off: "off",
52
57
  need_login: "First: orb44 login",
53
58
  key_revoked: "Key revoked. Again: orb44 login",
54
59
  daemon_run: "daemon every {sec}s · {host}",
@@ -64,6 +69,11 @@ const STR = {
64
69
  copy_key: "and copy the key into ORB44_DEVICE_FILE that user orb44 can read.",
65
70
  not_paired: "Not paired. orb44 login",
66
71
  now_on_box: "On the machine now",
72
+ ver_here: "On this machine",
73
+ ver_latest: "Latest",
74
+ ver_ok: "up to date",
75
+ ver_unknown: "npm unreachable",
76
+ ver_behind: "update: npx @orb44/cli@{ver} update --force",
67
77
  logged_out: "Disconnected. Cabinet dropped the device.",
68
78
  uninstall_ok: "Daemon stopped and unit removed. Pairing key kept.",
69
79
  uninstall_purged: "Daemon, key, and service user orb44 removed. Cabinet dropped the device.",
@@ -116,19 +126,21 @@ const STR = {
116
126
  preview_ssh_pass: "password",
117
127
  preview_ssh_key: "keys",
118
128
  preview_limited: "limited: cannot see which process owns the ports",
119
- help: `Orb44 satellite — admin device.
129
+ help: `Orb44 satellite {version} — admin device.
120
130
 
121
131
  orb44 login [--url http://127.0.0.1:8787] [--daemon] [--logs] [--force] [--lang en|ru|ko|es]
122
132
  orb44 pulse
123
133
  orb44 daemon [--interval 300]
124
- orb44 install [--system] [--logs] [--interval 300]
134
+ orb44 install [--system] [--daemon] [--logs] [--interval 300]
125
135
  orb44 uninstall [--purge]
126
136
  orb44 lang [en|ru|ko|es]
127
137
  orb44 status
138
+ orb44 version
128
139
  orb44 update
129
140
  orb44 logout
130
141
 
131
142
  Login asks language (saved), then daemon and logs (default no).
143
+ Install asks the same two (daemon default yes, logs default no). --daemon / --logs skip the questions.
132
144
  Key: {file}
133
145
  Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
134
146
  },
@@ -162,6 +174,11 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
162
174
  logs_yes: "Да — последние ошибки, если читаются",
163
175
  logs_skip: "Логи не снимаем. Позже: orb44 login --logs или orb44 install --logs",
164
176
  logs_on: "Логи включены. Docker/kube/nginx — только если этот пользователь их видит.",
177
+ grant_process: "Системные процессы",
178
+ grant_daemon: "Рестарт после загрузки",
179
+ grant_logs: "Мониторинг логов",
180
+ grant_on: "да",
181
+ grant_off: "нет",
165
182
  need_login: "Сначала: orb44 login",
166
183
  key_revoked: "Ключ отозван. Снова: orb44 login",
167
184
  daemon_run: "демон каждые {sec}с · {host}",
@@ -177,6 +194,11 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
177
194
  copy_key: "и скопируйте ключ в ORB44_DEVICE_FILE, который читает orb44.",
178
195
  not_paired: "Не связано. orb44 login",
179
196
  now_on_box: "Сейчас на машине",
197
+ ver_here: "На машине",
198
+ ver_latest: "Актуальная",
199
+ ver_ok: "совпадает",
200
+ ver_unknown: "npm не ответил",
201
+ ver_behind: "обновить: npx @orb44/cli@{ver} update --force",
180
202
  logged_out: "Отключено. В кабинете устройство снято.",
181
203
  uninstall_ok: "Демон остановлен, unit снят. Ключ пары оставлен.",
182
204
  uninstall_purged: "Демон, ключ и пользователь orb44 сняты. В кабинете устройство отозвано.",
@@ -229,19 +251,21 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
229
251
  preview_ssh_pass: "пароль",
230
252
  preview_ssh_key: "ключи",
231
253
  preview_limited: "ограничено: не видно, какой процесс слушает порты",
232
- help: `Orb44 сателлит — устройство админа.
254
+ help: `Orb44 сателлит {version} — устройство админа.
233
255
 
234
256
  orb44 login [--url http://127.0.0.1:8787] [--daemon] [--logs] [--force] [--lang en|ru|ko|es]
235
257
  orb44 pulse
236
258
  orb44 daemon [--interval 300]
237
- orb44 install [--system] [--logs] [--interval 300]
259
+ orb44 install [--system] [--daemon] [--logs] [--interval 300]
238
260
  orb44 uninstall [--purge]
239
261
  orb44 lang [en|ru|ko|es]
240
262
  orb44 status
263
+ orb44 version
241
264
  orb44 update
242
265
  orb44 logout
243
266
 
244
267
  После login спрашивает язык (запоминает), затем демон и логи — по умолчанию нет.
268
+ install спрашивает то же (демон — да, логи — нет). --daemon / --logs пропускают вопросы.
245
269
  Ключ: {file}
246
270
  Пульс исходящий. Кабинет не выполняет команды: отвечает текстом «что сделать».`,
247
271
  },
@@ -275,6 +299,11 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
275
299
  logs_yes: "예 — 읽을 수 있으면 마지막 오류",
276
300
  logs_skip: "로그 수집 안 함. 나중에: orb44 login --logs 또는 orb44 install --logs",
277
301
  logs_on: "로그 수집 켜짐. Docker/kube/nginx는 이 사용자가 읽을 수 있을 때만.",
302
+ grant_process: "시스템 프로세스",
303
+ grant_daemon: "부팅 후 재시작",
304
+ grant_logs: "로그 모니터링",
305
+ grant_on: "켜짐",
306
+ grant_off: "꺼짐",
278
307
  need_login: "먼저: orb44 login",
279
308
  key_revoked: "키가 취소되었습니다. 다시: orb44 login",
280
309
  daemon_run: "데몬 {sec}초마다 · {host}",
@@ -290,6 +319,11 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
290
319
  copy_key: "그리고 orb44가 읽을 ORB44_DEVICE_FILE로 키를 복사하세요.",
291
320
  not_paired: "연결되지 않음. orb44 login",
292
321
  now_on_box: "지금 이 기기",
322
+ ver_here: "이 기기",
323
+ ver_latest: "최신",
324
+ ver_ok: "최신",
325
+ ver_unknown: "npm 응답 없음",
326
+ ver_behind: "업데이트: npx @orb44/cli@{ver} update --force",
293
327
  logged_out: "해제됨. 콘솔에서 장치가 제거되었습니다.",
294
328
  uninstall_ok: "데몬을 멈추고 unit을 제거했습니다. 페어링 키는 남겼습니다.",
295
329
  uninstall_purged: "데몬, 키, 사용자 orb44를 제거했습니다. 콘솔에서 장치를 취소했습니다.",
@@ -342,19 +376,21 @@ Outgoing pulse. Cabinet does not execute commands; it replies with advice.`,
342
376
  preview_ssh_pass: "비밀번호",
343
377
  preview_ssh_key: "키",
344
378
  preview_limited: "제한: 포트를 연 프로세스를 볼 수 없음",
345
- help: `Orb44 위성 — 관리자 장치.
379
+ help: `Orb44 위성 {version} — 관리자 장치.
346
380
 
347
381
  orb44 login [--url http://127.0.0.1:8787] [--daemon] [--logs] [--force] [--lang en|ru|ko|es]
348
382
  orb44 pulse
349
383
  orb44 daemon [--interval 300]
350
- orb44 install [--system] [--logs] [--interval 300]
384
+ orb44 install [--system] [--daemon] [--logs] [--interval 300]
351
385
  orb44 uninstall [--purge]
352
386
  orb44 lang [en|ru|ko|es]
353
387
  orb44 status
388
+ orb44 version
354
389
  orb44 update
355
390
  orb44 logout
356
391
 
357
392
  login에서 언어를 묻고 저장한 뒤, 데몬과 로그는 기본값 아니오입니다.
393
+ install도 같은 두 질문(데몬 기본 예, 로그 기본 아니오). --daemon / --logs는 질문을 건너뜁니다.
358
394
  키: {file}
359
395
  나가는 펄스. 콘솔은 명령을 실행하지 않고 조언만 돌려줍니다.`,
360
396
  },
@@ -388,6 +424,11 @@ login에서 언어를 묻고 저장한 뒤, 데몬과 로그는 기본값 아니
388
424
  logs_yes: "Sí — últimos errores si se pueden leer",
389
425
  logs_skip: "Sin logs. Luego: orb44 login --logs o orb44 install --logs",
390
426
  logs_on: "Logs activos. Docker/kube/nginx solo si este usuario los ve.",
427
+ grant_process: "Procesos del sistema",
428
+ grant_daemon: "Reinicio tras el arranque",
429
+ grant_logs: "Monitor de logs",
430
+ grant_on: "sí",
431
+ grant_off: "no",
391
432
  need_login: "Primero: orb44 login",
392
433
  key_revoked: "Clave revocada. Otra vez: orb44 login",
393
434
  daemon_run: "demonio cada {sec}s · {host}",
@@ -403,6 +444,11 @@ login에서 언어를 묻고 저장한 뒤, 데몬과 로그는 기본값 아니
403
444
  copy_key: "y copie la clave a ORB44_DEVICE_FILE que pueda leer orb44.",
404
445
  not_paired: "Sin vincular. orb44 login",
405
446
  now_on_box: "Ahora en la máquina",
447
+ ver_here: "En esta máquina",
448
+ ver_latest: "Actual",
449
+ ver_ok: "al día",
450
+ ver_unknown: "npm no respondió",
451
+ ver_behind: "actualizar: npx @orb44/cli@{ver} update --force",
406
452
  logged_out: "Desconectado. El gabinete quitó el dispositivo.",
407
453
  uninstall_ok: "Demonio parado y unit quitado. Se guarda la clave de emparejamiento.",
408
454
  uninstall_purged: "Demonio, clave y usuario orb44 eliminados. El gabinete revocó el dispositivo.",
@@ -455,19 +501,21 @@ login에서 언어를 묻고 저장한 뒤, 데몬과 로그는 기본값 아니
455
501
  preview_ssh_pass: "contraseña",
456
502
  preview_ssh_key: "claves",
457
503
  preview_limited: "limitado: no se ve qué proceso tiene los puertos",
458
- help: `Satélite Orb44 — dispositivo de admin.
504
+ help: `Satélite Orb44 {version} — dispositivo de admin.
459
505
 
460
506
  orb44 login [--url http://127.0.0.1:8787] [--daemon] [--logs] [--force] [--lang en|ru|ko|es]
461
507
  orb44 pulse
462
508
  orb44 daemon [--interval 300]
463
- orb44 install [--system] [--logs] [--interval 300]
509
+ orb44 install [--system] [--daemon] [--logs] [--interval 300]
464
510
  orb44 uninstall [--purge]
465
511
  orb44 lang [en|ru|ko|es]
466
512
  orb44 status
513
+ orb44 version
467
514
  orb44 update
468
515
  orb44 logout
469
516
 
470
517
  Login pregunta idioma (lo guarda), luego demonio y logs (por defecto no).
518
+ install pregunta lo mismo (demonio sí, logs no). --daemon / --logs saltan las preguntas.
471
519
  Clave: {file}
472
520
  Pulso saliente. El gabinete no ejecuta órdenes; responde con consejos.`,
473
521
  },