pinomad 0.13.0 → 0.14.1

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.
Files changed (41) hide show
  1. package/dist/{chunk-kmzzjv53.js → chunk-1mjbt2z2.js} +143 -10
  2. package/dist/{chunk-90g1cg9n.js → chunk-3hfaejdx.js} +1 -1
  3. package/dist/{chunk-d9mq5d46.js → chunk-5ayqca95.js} +10 -8
  4. package/dist/{chunk-7mn38n4f.js → chunk-63ymn5c9.js} +2 -2
  5. package/dist/{chunk-563fnad9.js → chunk-6j6hkfbj.js} +8 -4
  6. package/dist/{chunk-pqe7q1s7.js → chunk-6vbp1vva.js} +2 -1
  7. package/dist/chunk-8g2e77gf.js +46 -0
  8. package/dist/{chunk-6th9xv39.js → chunk-97ssw1c0.js} +9 -7
  9. package/dist/{chunk-g3ahp7b9.js → chunk-9trbbz4r.js} +1 -1
  10. package/dist/{chunk-4fferbxw.js → chunk-e59k3bmz.js} +213 -30
  11. package/dist/{chunk-s0h7c7da.js → chunk-ega1wnkg.js} +1 -1
  12. package/dist/{chunk-maqv34cs.js → chunk-evbv1fkn.js} +3 -3
  13. package/dist/{chunk-d4tq62yr.js → chunk-f6741a5q.js} +12 -11
  14. package/dist/{chunk-m51mq8vh.js → chunk-fdhbzwxj.js} +12 -10
  15. package/dist/{chunk-aapsc9g0.js → chunk-hfwa1vt5.js} +1952 -295
  16. package/dist/{chunk-t91zt5f0.js → chunk-hg9gs396.js} +1 -1
  17. package/dist/chunk-mdjk0s0t.js +23 -0
  18. package/dist/{chunk-wd7aracm.js → chunk-mxwcnnkg.js} +1 -303
  19. package/dist/chunk-pte4peaf.js +315 -0
  20. package/dist/{chunk-53xv3fny.js → chunk-s66evzar.js} +2446 -416
  21. package/dist/chunk-vedqqhbd.js +240 -0
  22. package/dist/{chunk-ra86wjp5.js → chunk-w9zpff3n.js} +11 -6
  23. package/dist/pinomad.js +12 -12
  24. package/package.json +5 -1
  25. package/web/assets/{core-BHm2gdHL.js → core-BWHGsFpV.js} +1 -1
  26. package/web/assets/{highlighted-diff-DrHvSLK9.js → highlighted-diff-DJ7KZCpS.js} +2 -2
  27. package/web/assets/{highlights-1aLwssz-.js → highlights-CyEmo6OI.js} +1 -1
  28. package/web/assets/{highlights-themes-C1p4pFYS.js → highlights-themes-CSNkBojy.js} +1 -1
  29. package/web/assets/index-C_qkbyL7.css +1 -0
  30. package/web/assets/index-DefQtCI2.js +396 -0
  31. package/web/assets/{shiki-BwyCm3kZ.js → shiki-BzCmRG-v.js} +2 -2
  32. package/web/assets/{shiki-langs-CMlALLSg.js → shiki-langs-DOkjyV4d.js} +1 -1
  33. package/web/assets/{stream-tokenizer-BlgIhw0y.js → stream-tokenizer-CBPqFe4Z.js} +1 -1
  34. package/web/assets/{theming-themes-DDvoqEqT.js → theming-themes-wKVca0aB.js} +1 -1
  35. package/web/assets/{xterm-view-BnKOnF3C.js → xterm-view-CKa1-QCM.js} +12 -12
  36. package/web/index.html +3 -2
  37. package/web/theme-boot.js +11 -0
  38. package/dist/chunk-sd640dt7.js +0 -22
  39. package/dist/chunk-t6fw0wa9.js +0 -96
  40. package/web/assets/index-A_AUJoO6.css +0 -1
  41. package/web/assets/index-BafYMKiN.js +0 -396
@@ -3,7 +3,7 @@ import {
3
3
  generateKeyPair,
4
4
  keyPairFromPrivate,
5
5
  toBase64Url
6
- } from "./chunk-pqe7q1s7.js";
6
+ } from "./chunk-6vbp1vva.js";
7
7
 
8
8
  // apps/host/src/devices.ts
9
9
  import { link, readFile, unlink, writeFile } from "node:fs/promises";
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ joinServer,
4
+ main
5
+ } from "./chunk-5ayqca95.js";
6
+ import"./chunk-63ymn5c9.js";
7
+ import"./chunk-6j6hkfbj.js";
8
+ import"./chunk-hg9gs396.js";
9
+ import"./chunk-nq57fdnq.js";
10
+ import"./chunk-9trbbz4r.js";
11
+ import"./chunk-pte4peaf.js";
12
+ import"./chunk-e59k3bmz.js";
13
+ import"./chunk-kzbzacz9.js";
14
+ import"./chunk-mxwcnnkg.js";
15
+ import"./chunk-1mjbt2z2.js";
16
+ import"./chunk-6vbp1vva.js";
17
+ import"./chunk-ngf1zatm.js";
18
+ import"./chunk-ega1wnkg.js";
19
+ import"./chunk-df32avw6.js";
20
+ export {
21
+ main,
22
+ joinServer
23
+ };
@@ -1,27 +1,3 @@
1
- import {
2
- ProtocolMismatchError,
3
- connectRemoteDurable
4
- } from "./chunk-4fferbxw.js";
5
- import {
6
- isParseArgsError
7
- } from "./chunk-kzbzacz9.js";
8
- import {
9
- DEFAULT_DATA_DIR,
10
- hostAddress
11
- } from "./chunk-ngf1zatm.js";
12
- import {
13
- commandHint,
14
- hostEntry,
15
- packagedVersion
16
- } from "./chunk-s0h7c7da.js";
17
-
18
- // apps/host/src/cli/service.ts
19
- import { execFile as execFile2 } from "node:child_process";
20
- import { homedir as homedir2 } from "node:os";
21
- import { resolve as resolve2 } from "node:path";
22
- import { fileURLToPath } from "node:url";
23
- import { parseArgs, promisify as promisify2 } from "node:util";
24
-
25
1
  // apps/host/src/service/definition.ts
26
2
  import { join, resolve } from "node:path";
27
3
  var LAUNCHER_EXECUTABLE = "pinomad-host";
@@ -219,37 +195,6 @@ WantedBy=default.target
219
195
  `;
220
196
  }
221
197
 
222
- // apps/host/src/service/idle.ts
223
- async function waitForIdle(remote, onBusy) {
224
- if (remote.view.current().tasks === undefined)
225
- await remote.controller.toggleTasks();
226
- let announced = false;
227
- await new Promise((resolve2) => {
228
- const check = () => {
229
- const view = remote.view.current();
230
- if (view.connection !== "connected") {
231
- unsubscribe();
232
- resolve2();
233
- return;
234
- }
235
- const tasks = view.tasks;
236
- if (tasks === undefined)
237
- return;
238
- if (Object.keys(tasks.tasks).length === 0) {
239
- unsubscribe();
240
- resolve2();
241
- return;
242
- }
243
- if (!announced) {
244
- announced = true;
245
- onBusy(tasks);
246
- }
247
- };
248
- const unsubscribe = remote.view.subscribe(check);
249
- check();
250
- });
251
- }
252
-
253
198
  // apps/host/src/service/manager.ts
254
199
  import { execFile, spawn } from "node:child_process";
255
200
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
@@ -428,251 +373,4 @@ function serviceManager(platform = process.platform) {
428
373
  throw new Error(`service commands support macOS and Linux, not ${platform}`);
429
374
  }
430
375
 
431
- // apps/host/src/cli/service.ts
432
- var run2 = promisify2(execFile2);
433
- var repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
434
- var message = (error) => error instanceof Error ? error.message : String(error);
435
- function connectToHost(url, token, timeoutMs = 3000) {
436
- const connecting = connectRemoteDurable({ url, token, reconnectDelayMs: { min: 200, max: 2000 } });
437
- const timedOut = Symbol("timedOut");
438
- return Promise.race([
439
- connecting,
440
- new Promise((resolve3) => {
441
- const timer = setTimeout(() => resolve3(timedOut), timeoutMs);
442
- timer.unref();
443
- })
444
- ]).then((winner) => {
445
- if (winner !== timedOut)
446
- return winner;
447
- connecting.then((remote) => remote.close(), () => {});
448
- throw new Error("connect timed out");
449
- });
450
- }
451
- async function install(argv) {
452
- const spec = installSpec(argv, {
453
- execPath: process.execPath,
454
- env: process.env,
455
- home: homedir2(),
456
- cwd: process.cwd(),
457
- mainPath: hostEntry.script,
458
- entryArgs: hostEntry.args
459
- });
460
- const path = await serviceManager().install(spec);
461
- console.log(`installed ${path}`);
462
- console.log(`data dir: ${spec.dataDir}`);
463
- console.log(`browser link: ${commandHint("link")} pairing QR: ${commandHint("pair")}`);
464
- }
465
- async function waitUntilIdle(address, connect, log) {
466
- try {
467
- const remote = await connect(address.url, address.token);
468
- await waitForIdle(remote, (tasks) => {
469
- log("waiting for running tasks to finish (Ctrl-C to cancel)");
470
- for (const task of Object.values(tasks.tasks)) {
471
- log(` ${task.kind} in conversation ${task.conversationId}`);
472
- }
473
- });
474
- remote.close();
475
- } catch {}
476
- }
477
- async function stopService({
478
- force,
479
- argv,
480
- manager = serviceManager(),
481
- connect = connectToHost,
482
- log = (line) => console.log(line),
483
- logError = (line) => console.error(line)
484
- }) {
485
- const state = await manager.state();
486
- if (!state.installed) {
487
- log(`service not installed (${commandHint("service")} install)`);
488
- return 1;
489
- }
490
- if (state.stopped) {
491
- log("already stopped");
492
- return 0;
493
- }
494
- if (!force) {
495
- const spec = argv.length === 0 ? await manager.read() : undefined;
496
- const port = spec === undefined ? undefined : argValue(spec.hostArgs, "--port");
497
- const flags = spec === undefined ? argv : ["--data-dir", spec.dataDir, ...port === undefined ? [] : ["--url", `ws://127.0.0.1:${port}`]];
498
- const address = await hostAddress(flags).catch((error) => {
499
- if (isParseArgsError(error))
500
- throw error;
501
- return;
502
- });
503
- if (address !== undefined)
504
- await waitUntilIdle(address, connect, log);
505
- }
506
- const holdInterrupt = () => {};
507
- process.on("SIGINT", holdInterrupt);
508
- try {
509
- await manager.stop();
510
- } finally {
511
- process.off("SIGINT", holdInterrupt);
512
- }
513
- const after = await manager.state();
514
- if (!after.stopped) {
515
- logError(`the host is still running (${after.detail}); run \`${commandHint("service")} stop\` again`);
516
- return 1;
517
- }
518
- log(`stopped; it stays off, also after a restart, until \`${commandHint("service")} start\``);
519
- return 0;
520
- }
521
- async function startService({
522
- manager = serviceManager(),
523
- log = (line) => console.log(line)
524
- } = {}) {
525
- if (!(await manager.state()).installed) {
526
- log(`service not installed (${commandHint("service")} install)`);
527
- return 1;
528
- }
529
- await manager.start();
530
- log("started");
531
- return 0;
532
- }
533
- async function versionLine() {
534
- if (packagedVersion !== undefined)
535
- return `version: ${packagedVersion}`;
536
- const head = await run2("git", ["rev-parse", "--short", "HEAD"], { cwd: repoRoot }).then(({ stdout }) => stdout.trim(), () => "unknown");
537
- return `checkout: ${head}`;
538
- }
539
- async function reachabilityLine(argv) {
540
- try {
541
- const { url, token } = await hostAddress(argv);
542
- const remote = await connectToHost(url, token);
543
- if (remote.view.current().tasks === undefined)
544
- await remote.controller.toggleTasks();
545
- const tasks = remote.view.current().tasks;
546
- const count = tasks === undefined ? 0 : Object.keys(tasks.tasks).length;
547
- remote.close();
548
- return `host: reachable at ${url}, ${count} live task${count === 1 ? "" : "s"}`;
549
- } catch (error) {
550
- if (isParseArgsError(error))
551
- throw error;
552
- return `host: unreachable (${message(error)})`;
553
- }
554
- }
555
- var serviceStatusJson = (state) => JSON.stringify({
556
- installed: state.installed,
557
- stopped: state.stopped,
558
- running: state.running,
559
- ...state.pid === undefined ? {} : { pid: state.pid },
560
- detail: state.detail
561
- });
562
- async function status(argv) {
563
- const state = await serviceManager().state();
564
- if (argv.includes("--json")) {
565
- console.log(serviceStatusJson(state));
566
- return;
567
- }
568
- console.log(`service: ${state.installed ? state.detail : "not installed"}`);
569
- console.log(await versionLine());
570
- console.log(await reachabilityLine(argv));
571
- }
572
- async function restartService({
573
- force,
574
- argv,
575
- manager = serviceManager(),
576
- restart,
577
- connect = connectToHost,
578
- pollTimeoutMs = 30000,
579
- pollDelayMs = 500
580
- }) {
581
- const state = await manager.state();
582
- if (!state.installed) {
583
- console.log(`service not installed (${commandHint("service")} install)`);
584
- return 1;
585
- }
586
- if (state.stopped && restart === undefined) {
587
- console.log(`service stopped (${commandHint("service")} start)`);
588
- return 1;
589
- }
590
- const address = await hostAddress(argv).catch((error) => {
591
- if (isParseArgsError(error))
592
- throw error;
593
- return;
594
- });
595
- if (!force && address !== undefined)
596
- await waitUntilIdle(address, connect, (line) => console.log(line));
597
- await (restart?.() ?? manager.restart());
598
- if (address === undefined) {
599
- console.log("restart requested (host address unknown; not polling)");
600
- return 0;
601
- }
602
- const deadline = Date.now() + pollTimeoutMs;
603
- for (;; ) {
604
- try {
605
- const remote = await connect(address.url, address.token, 2000);
606
- remote.close();
607
- console.log(`host restarted, reachable at ${address.url}`);
608
- return 0;
609
- } catch (error) {
610
- if (error instanceof ProtocolMismatchError && error.direction === "client-older") {
611
- const newer = error.hostVersion ?? `protocol major ${error.hostMajor}`;
612
- console.log(`host restarted (${newer}, newer than this upgrader), reachable at ${address.url}`);
613
- return 0;
614
- }
615
- if (Date.now() > deadline) {
616
- console.error(`host did not answer within ${pollTimeoutMs / 1000}s after restart: ${message(error)}`);
617
- return 1;
618
- }
619
- await new Promise((resolve3) => setTimeout(resolve3, pollDelayMs));
620
- }
621
- }
622
- }
623
- async function logs(argv) {
624
- const { values } = parseArgs({
625
- args: [...argv],
626
- options: {
627
- follow: { type: "boolean", default: false },
628
- lines: { type: "string", short: "n", default: "100" },
629
- "data-dir": { type: "string" }
630
- }
631
- });
632
- const dataDir = resolve2(values["data-dir"] ?? DEFAULT_DATA_DIR);
633
- await serviceManager().logs(dataDir, Number(values.lines), values.follow);
634
- }
635
- async function main(argv) {
636
- const [command, ...args] = argv;
637
- try {
638
- switch (command) {
639
- case "install":
640
- await install(args);
641
- break;
642
- case "uninstall":
643
- await serviceManager().uninstall();
644
- console.log("uninstalled");
645
- break;
646
- case "status":
647
- await status(args);
648
- break;
649
- case "restart": {
650
- const force = args.includes("--force");
651
- process.exitCode = await restartService({ force, argv: args.filter((arg) => arg !== "--force") });
652
- break;
653
- }
654
- case "stop": {
655
- const force = args.includes("--force");
656
- process.exitCode = await stopService({ force, argv: args.filter((arg) => arg !== "--force") });
657
- break;
658
- }
659
- case "start":
660
- process.exitCode = await startService();
661
- break;
662
- case "logs":
663
- await logs(args);
664
- break;
665
- default:
666
- console.error(`usage: ${commandHint("service")} install|uninstall|status|restart|stop|start|logs`);
667
- process.exitCode = 1;
668
- }
669
- } catch (error) {
670
- if (isParseArgsError(error))
671
- throw error;
672
- console.error(message(error));
673
- process.exitCode = 1;
674
- }
675
- }
676
- if (false) {}
677
-
678
- export { LAUNCHER_EXECUTABLE, isLauncher, installSpec, argValue, withoutArg, withoutRelayArgs, serviceManager, stopService, startService, versionLine, reachabilityLine, serviceStatusJson, restartService, main };
376
+ export { LAUNCHER_EXECUTABLE, isLauncher, installSpec, argValue, withoutArg, withoutRelayArgs, serviceManager };
@@ -0,0 +1,315 @@
1
+ import {
2
+ ProtocolMismatchError,
3
+ connectRemoteDurable
4
+ } from "./chunk-e59k3bmz.js";
5
+ import {
6
+ isParseArgsError
7
+ } from "./chunk-kzbzacz9.js";
8
+ import {
9
+ argValue,
10
+ installSpec,
11
+ serviceManager
12
+ } from "./chunk-mxwcnnkg.js";
13
+ import {
14
+ DEFAULT_DATA_DIR,
15
+ hostAddress
16
+ } from "./chunk-ngf1zatm.js";
17
+ import {
18
+ commandHint,
19
+ hostEntry,
20
+ packagedVersion
21
+ } from "./chunk-ega1wnkg.js";
22
+
23
+ // apps/host/src/cli/service.ts
24
+ import { execFile } from "node:child_process";
25
+ import { homedir } from "node:os";
26
+ import { resolve } from "node:path";
27
+ import { fileURLToPath } from "node:url";
28
+ import { parseArgs, promisify } from "node:util";
29
+
30
+ // apps/host/src/service/idle.ts
31
+ async function waitForIdle(remote, onBusy) {
32
+ if (remote.view.current().tasks === undefined)
33
+ await remote.controller.toggleTasks();
34
+ let announced = false;
35
+ await new Promise((resolve) => {
36
+ const check = () => {
37
+ const view = remote.view.current();
38
+ if (view.connection !== "connected") {
39
+ unsubscribe();
40
+ resolve();
41
+ return;
42
+ }
43
+ const tasks = view.tasks;
44
+ if (tasks === undefined)
45
+ return;
46
+ if (Object.keys(tasks.tasks).length === 0) {
47
+ unsubscribe();
48
+ resolve();
49
+ return;
50
+ }
51
+ if (!announced) {
52
+ announced = true;
53
+ onBusy(tasks);
54
+ }
55
+ };
56
+ const unsubscribe = remote.view.subscribe(check);
57
+ check();
58
+ });
59
+ }
60
+
61
+ // apps/host/src/cli/service.ts
62
+ var run = promisify(execFile);
63
+ var repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
64
+ var message = (error) => error instanceof Error ? error.message : String(error);
65
+ function connectToHost(url, token, timeoutMs = 3000) {
66
+ const connecting = connectRemoteDurable({ url, token, reconnectDelayMs: { min: 200, max: 2000 } });
67
+ const timedOut = Symbol("timedOut");
68
+ return Promise.race([
69
+ connecting,
70
+ new Promise((resolve2) => {
71
+ const timer = setTimeout(() => resolve2(timedOut), timeoutMs);
72
+ timer.unref();
73
+ })
74
+ ]).then((winner) => {
75
+ if (winner !== timedOut)
76
+ return winner;
77
+ connecting.then((remote) => remote.close(), () => {});
78
+ throw new Error("connect timed out");
79
+ });
80
+ }
81
+ async function install(argv) {
82
+ const spec = installSpec(argv, {
83
+ execPath: process.execPath,
84
+ env: process.env,
85
+ home: homedir(),
86
+ cwd: process.cwd(),
87
+ mainPath: hostEntry.script,
88
+ entryArgs: hostEntry.args
89
+ });
90
+ const path = await serviceManager().install(spec);
91
+ console.log(`installed ${path}`);
92
+ console.log(`data dir: ${spec.dataDir}`);
93
+ console.log(`browser link: ${commandHint("link")} pairing QR: ${commandHint("pair")}`);
94
+ }
95
+ async function waitUntilIdle(address, connect, log) {
96
+ try {
97
+ const remote = await connect(address.url, address.token);
98
+ await waitForIdle(remote, (tasks) => {
99
+ log("waiting for running tasks to finish (Ctrl-C to cancel)");
100
+ for (const task of Object.values(tasks.tasks)) {
101
+ log(` ${task.kind} in conversation ${task.conversationId}`);
102
+ }
103
+ });
104
+ remote.close();
105
+ } catch {}
106
+ }
107
+ async function stopService({
108
+ force,
109
+ argv,
110
+ manager = serviceManager(),
111
+ connect = connectToHost,
112
+ log = (line) => console.log(line),
113
+ logError = (line) => console.error(line)
114
+ }) {
115
+ const state = await manager.state();
116
+ if (!state.installed) {
117
+ log(`service not installed (${commandHint("service")} install)`);
118
+ return 1;
119
+ }
120
+ if (state.stopped) {
121
+ log("already stopped");
122
+ return 0;
123
+ }
124
+ if (!force) {
125
+ const spec = argv.length === 0 ? await manager.read() : undefined;
126
+ const port = spec === undefined ? undefined : argValue(spec.hostArgs, "--port");
127
+ const flags = spec === undefined ? argv : ["--data-dir", spec.dataDir, ...port === undefined ? [] : ["--url", `ws://127.0.0.1:${port}`]];
128
+ const address = await hostAddress(flags).catch((error) => {
129
+ if (isParseArgsError(error))
130
+ throw error;
131
+ return;
132
+ });
133
+ if (address !== undefined)
134
+ await waitUntilIdle(address, connect, log);
135
+ }
136
+ const holdInterrupt = () => {};
137
+ process.on("SIGINT", holdInterrupt);
138
+ try {
139
+ await manager.stop();
140
+ } finally {
141
+ process.off("SIGINT", holdInterrupt);
142
+ }
143
+ const after = await manager.state();
144
+ if (!after.stopped) {
145
+ logError(`the host is still running (${after.detail}); run \`${commandHint("service")} stop\` again`);
146
+ return 1;
147
+ }
148
+ log(`stopped; it stays off, also after a restart, until \`${commandHint("service")} start\``);
149
+ return 0;
150
+ }
151
+ async function startService({
152
+ manager = serviceManager(),
153
+ log = (line) => console.log(line)
154
+ } = {}) {
155
+ if (!(await manager.state()).installed) {
156
+ log(`service not installed (${commandHint("service")} install)`);
157
+ return 1;
158
+ }
159
+ await manager.start();
160
+ log("started");
161
+ return 0;
162
+ }
163
+ async function versionLine() {
164
+ if (packagedVersion !== undefined)
165
+ return `version: ${packagedVersion}`;
166
+ const head = await run("git", ["rev-parse", "--short", "HEAD"], { cwd: repoRoot }).then(({ stdout }) => stdout.trim(), () => "unknown");
167
+ return `checkout: ${head}`;
168
+ }
169
+ async function reachabilityLine(argv) {
170
+ try {
171
+ const { url, token } = await hostAddress(argv);
172
+ const remote = await connectToHost(url, token);
173
+ if (remote.view.current().tasks === undefined)
174
+ await remote.controller.toggleTasks();
175
+ const tasks = remote.view.current().tasks;
176
+ const count = tasks === undefined ? 0 : Object.keys(tasks.tasks).length;
177
+ remote.close();
178
+ return `host: reachable at ${url}, ${count} live task${count === 1 ? "" : "s"}`;
179
+ } catch (error) {
180
+ if (isParseArgsError(error))
181
+ throw error;
182
+ return `host: unreachable (${message(error)})`;
183
+ }
184
+ }
185
+ var serviceStatusJson = (state) => JSON.stringify({
186
+ installed: state.installed,
187
+ stopped: state.stopped,
188
+ running: state.running,
189
+ ...state.pid === undefined ? {} : { pid: state.pid },
190
+ detail: state.detail
191
+ });
192
+ async function status(argv) {
193
+ const state = await serviceManager().state();
194
+ if (argv.includes("--json")) {
195
+ console.log(serviceStatusJson(state));
196
+ return;
197
+ }
198
+ console.log(`service: ${state.installed ? state.detail : "not installed"}`);
199
+ console.log(await versionLine());
200
+ console.log(await reachabilityLine(argv));
201
+ }
202
+ async function restartService({
203
+ force,
204
+ argv,
205
+ manager = serviceManager(),
206
+ restart,
207
+ connect = connectToHost,
208
+ pollTimeoutMs = 30000,
209
+ pollDelayMs = 500
210
+ }) {
211
+ const state = await manager.state();
212
+ if (!state.installed) {
213
+ console.log(`service not installed (${commandHint("service")} install)`);
214
+ return 1;
215
+ }
216
+ if (state.stopped && restart === undefined) {
217
+ console.log(`service stopped (${commandHint("service")} start)`);
218
+ return 1;
219
+ }
220
+ const address = await hostAddress(argv).catch((error) => {
221
+ if (isParseArgsError(error))
222
+ throw error;
223
+ return;
224
+ });
225
+ if (!force && address !== undefined)
226
+ await waitUntilIdle(address, connect, (line) => console.log(line));
227
+ await (restart?.() ?? manager.restart());
228
+ if (address === undefined) {
229
+ console.log("restart requested (host address unknown; not polling)");
230
+ return 0;
231
+ }
232
+ return awaitRestarted(address, { connect, pollTimeoutMs, pollDelayMs });
233
+ }
234
+ async function awaitRestarted(address, {
235
+ connect = connectToHost,
236
+ pollTimeoutMs = 30000,
237
+ pollDelayMs = 500
238
+ } = {}) {
239
+ const deadline = Date.now() + pollTimeoutMs;
240
+ for (;; ) {
241
+ try {
242
+ const remote = await connect(address.url, address.token, 2000);
243
+ remote.close();
244
+ console.log(`host restarted, reachable at ${address.url}`);
245
+ return 0;
246
+ } catch (error) {
247
+ if (error instanceof ProtocolMismatchError && error.direction === "client-older") {
248
+ const newer = error.hostVersion ?? `protocol major ${error.hostMajor}`;
249
+ console.log(`host restarted (${newer}, newer than this upgrader), reachable at ${address.url}`);
250
+ return 0;
251
+ }
252
+ if (Date.now() > deadline) {
253
+ console.error(`host did not answer within ${pollTimeoutMs / 1000}s after restart: ${message(error)}`);
254
+ return 1;
255
+ }
256
+ await new Promise((resolve2) => setTimeout(resolve2, pollDelayMs));
257
+ }
258
+ }
259
+ }
260
+ async function logs(argv) {
261
+ const { values } = parseArgs({
262
+ args: [...argv],
263
+ options: {
264
+ follow: { type: "boolean", default: false },
265
+ lines: { type: "string", short: "n", default: "100" },
266
+ "data-dir": { type: "string" }
267
+ }
268
+ });
269
+ const dataDir = resolve(values["data-dir"] ?? DEFAULT_DATA_DIR);
270
+ await serviceManager().logs(dataDir, Number(values.lines), values.follow);
271
+ }
272
+ async function main(argv) {
273
+ const [command, ...args] = argv;
274
+ try {
275
+ switch (command) {
276
+ case "install":
277
+ await install(args);
278
+ break;
279
+ case "uninstall":
280
+ await serviceManager().uninstall();
281
+ console.log("uninstalled");
282
+ break;
283
+ case "status":
284
+ await status(args);
285
+ break;
286
+ case "restart": {
287
+ const force = args.includes("--force");
288
+ process.exitCode = await restartService({ force, argv: args.filter((arg) => arg !== "--force") });
289
+ break;
290
+ }
291
+ case "stop": {
292
+ const force = args.includes("--force");
293
+ process.exitCode = await stopService({ force, argv: args.filter((arg) => arg !== "--force") });
294
+ break;
295
+ }
296
+ case "start":
297
+ process.exitCode = await startService();
298
+ break;
299
+ case "logs":
300
+ await logs(args);
301
+ break;
302
+ default:
303
+ console.error(`usage: ${commandHint("service")} install|uninstall|status|restart|stop|start|logs`);
304
+ process.exitCode = 1;
305
+ }
306
+ } catch (error) {
307
+ if (isParseArgsError(error))
308
+ throw error;
309
+ console.error(message(error));
310
+ process.exitCode = 1;
311
+ }
312
+ }
313
+ if (false) {}
314
+
315
+ export { connectToHost, stopService, startService, versionLine, reachabilityLine, serviceStatusJson, restartService, awaitRestarted, main };