@opentig/cli 0.1.2 → 0.1.4
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/dist/bin.mjs +58 -7
- package/dist/chunks/{cli-bEPXlEpH.mjs → cli-B3AR8LUd.mjs} +234 -170
- package/dist/chunks/cli-service-B939lTxw.mjs +237 -0
- package/dist/client/assets/App-BWpP-n84.js +118 -0
- package/dist/client/assets/{CreatePullRequestDialog-NPqtWmYL.js → CreatePullRequestDialog-CQKBUxKz.js} +2 -2
- package/dist/client/assets/{DiffWorkspace-CZH8jCtn.js → DiffWorkspace-Dg7YI5fJ.js} +6 -6
- package/dist/client/assets/EditableFileViewer-CmxzBnAY.js +1 -0
- package/dist/client/assets/{File-C25AAfq1.js → File-CYcpdoXz.js} +1 -1
- package/dist/client/assets/{FilesView-C6qX7ixR.js → FilesView-BFCwGLC2.js} +1 -1
- package/dist/client/assets/{GitHubAvatar-DV6lI4Jh.js → GitHubAvatar-BcncAgKT.js} +1 -1
- package/dist/client/assets/HistoryView-Dev4CVOY.js +1 -0
- package/dist/client/assets/{HtmlFileViewer-CiPZFmIx.js → HtmlFileViewer-jdBVtlNv.js} +1 -1
- package/dist/client/assets/{IconEdit-DZPhGn6H.js → IconEdit-DQZu_Rpb.js} +1 -1
- package/dist/client/assets/{IconFolderPlus-CE1ATVt-.js → IconFolderPlus-DvEWPQIQ.js} +1 -1
- package/dist/client/assets/ImageFileViewer-BW1MbklH.js +1 -0
- package/dist/client/assets/{LocalRefsDialog-DIFaZUiQ.js → LocalRefsDialog-9ggtgVW_.js} +1 -1
- package/dist/client/assets/{MarkdownFileViewer-Y9tvTC3N.js → MarkdownFileViewer-Bhrr1l2Q.js} +2 -2
- package/dist/client/assets/{PairingPage-rJKAimg3.js → PairingPage-CkRMPzli.js} +1 -1
- package/dist/client/assets/{PierreDiffViewer-BRQK_cuH.js → PierreDiffViewer-CYdNkBG9.js} +1 -1
- package/dist/client/assets/PierreEditBoundary-Cu19fc5Z.js +2 -0
- package/dist/client/assets/{PierreWorkerPool-CRVJ90kq.js → PierreWorkerPool-B2iHe3DC.js} +1 -1
- package/dist/client/assets/PullRequestDiff-DZRDxOx9.js +1 -0
- package/dist/client/assets/PullRequestViewer-Bsh-F3-d.js +2 -0
- package/dist/client/assets/PullRequestsView-Brg-sbGb.js +1 -0
- package/dist/client/assets/{QuickOpenDialog-CciIWIcs.js → QuickOpenDialog-CtJqcFuk.js} +1 -1
- package/dist/client/assets/RepositoryProjectsDialog-BIUnKMb-.js +1 -0
- package/dist/client/assets/SearchView-C5_R_0ZU.js +1 -0
- package/dist/client/assets/{SettingsDialog-B0XwVWYT.js → SettingsDialog-CyJA7ajO.js} +2 -2
- package/dist/client/assets/Viewer-xMTNRGDO.js +3 -0
- package/dist/client/assets/{abnfDiagram-N423BO3Z-DRTxjQR7.js → abnfDiagram-N423BO3Z-DYcwdF-j.js} +1 -1
- package/dist/client/assets/{arc-DlZI_By6.js → arc-CZ6a8_6G.js} +1 -1
- package/dist/client/assets/{architectureDiagram-T3A2C74G-BpcQblyb.js → architectureDiagram-T3A2C74G-CViM1eoQ.js} +1 -1
- package/dist/client/assets/base-ui-D4MeJpa3.js +1 -0
- package/dist/client/assets/{blockDiagram-VBNYF7ZC-BF55JK7V.js → blockDiagram-VBNYF7ZC-BzRc4Zb8.js} +1 -1
- package/dist/client/assets/{c4Diagram-5PPSVZJV-CkQ8c1Fd.js → c4Diagram-5PPSVZJV-BZsdylz9.js} +1 -1
- package/dist/client/assets/channel-DUwjky93.js +1 -0
- package/dist/client/assets/checkbox-iSOOddl1.js +1 -0
- package/dist/client/assets/{chunk-2GRJ4B5K-BsVfgXSJ.js → chunk-2GRJ4B5K-CsL1szop.js} +1 -1
- package/dist/client/assets/{chunk-2Q5K7J3B-hYvR7LDf.js → chunk-2Q5K7J3B-Dpm-BZHi.js} +1 -1
- package/dist/client/assets/{chunk-5RXB4S5H-B2TcxiXR.js → chunk-5RXB4S5H-BNNb0lga.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-TDJFncVJ.js → chunk-5VM5RSS4-CcXWQAK-.js} +1 -1
- package/dist/client/assets/{chunk-6Q2QTUOP-BDdSa8Zj.js → chunk-6Q2QTUOP-BIpZKHoj.js} +1 -1
- package/dist/client/assets/{chunk-GF5L2VYU-CUHPmM86.js → chunk-GF5L2VYU-CXSHzIYB.js} +1 -1
- package/dist/client/assets/{chunk-JWPE2WC7-Pq05eTDs.js → chunk-JWPE2WC7-DxFk0X7_.js} +1 -1
- package/dist/client/assets/{chunk-KBJHAD2P-QSlaIrVy.js → chunk-KBJHAD2P-WRKVeb4h.js} +1 -1
- package/dist/client/assets/{chunk-RYQCIY6F-C0P7HEQg.js → chunk-RYQCIY6F-Br5DeHdX.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-C_oHIOR7.js → chunk-XXDRQBXY-DFCzSljb.js} +1 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-BtqFLKHp.js +1 -0
- package/dist/client/assets/classDiagram-v2-OCEON4UE-BtqFLKHp.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-Du6jXfCO.js → cose-bilkent-JH36ORCC-CE8E-qIe.js} +1 -1
- package/dist/client/assets/{cynefin-VYW2F7L2-CTUvB8CJ.js → cynefin-VYW2F7L2-CHf3vLku.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-MW4NZA55-BLRqmW6C.js → cynefinDiagram-MW4NZA55-90txNnhw.js} +1 -1
- package/dist/client/assets/{dagre-VZM6K2ZE-DTAlXx2k.js → dagre-VZM6K2ZE-6somveWH.js} +1 -1
- package/dist/client/assets/{diagram-7IWD3JNH-Coh1c4kx.js → diagram-7IWD3JNH-D4GP5bhO.js} +1 -1
- package/dist/client/assets/{diagram-B4RE2ZJO-TahBzLDX.js → diagram-B4RE2ZJO-Cz4bx70D.js} +1 -1
- package/dist/client/assets/{diagram-LBJQPF4R-2uwXPdqa.js → diagram-LBJQPF4R-BXjlhC7t.js} +1 -1
- package/dist/client/assets/{diagram-Q27KOJAE-Bm4UNuoF.js → diagram-Q27KOJAE-B_dDT61b.js} +1 -1
- package/dist/client/assets/{diagram-UB23O5K3-dWga-ccy.js → diagram-UB23O5K3-BotmyDTm.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-BXEA7PRR-D0IK6JUi.js → ebnfDiagram-BXEA7PRR-CBey4stz.js} +1 -1
- package/dist/client/assets/edit-ready-context-D77R8XU8.js +1 -0
- package/dist/client/assets/{erDiagram-JOGREHBK-DouKd_mX.js → erDiagram-JOGREHBK-B2g7aHUP.js} +1 -1
- package/dist/client/assets/{flowDiagram-UKHOOZJN-DQQX82AJ.js → flowDiagram-UKHOOZJN-B181B3KJ.js} +1 -1
- package/dist/client/assets/{ganttDiagram-PKOTCBZU-CbvAYRQc.js → ganttDiagram-PKOTCBZU-BFslA07w.js} +1 -1
- package/dist/client/assets/{gh-utils-XOjL-WGw.js → gh-utils-rGdT2YZN.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-D7cqbpF-.js → gitGraphDiagram-DS77QQ5N-B_uJt_Hp.js} +1 -1
- package/dist/client/assets/{index-Bm8fY0Qs.css → index-DXR6FOp1.css} +1 -1
- package/dist/client/assets/index-DaaX_e8C.js +3 -0
- package/dist/client/assets/{infoDiagram-6WML65LV-C0NfpA-J.js → infoDiagram-6WML65LV-BuajoWMd.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-DhIW58so.js → ishikawaDiagram-WSZJBQD7-CGRAyQ-L.js} +1 -1
- package/dist/client/assets/{journeyDiagram-NVQOT4AX-DqZZm_oH.js → journeyDiagram-NVQOT4AX-D8bgj_4i.js} +1 -1
- package/dist/client/assets/{kanban-definition-27J2QSJJ-DpSYxBwt.js → kanban-definition-27J2QSJJ-QrwKHnlk.js} +1 -1
- package/dist/client/assets/{linear-DRxvRS4v.js → linear-BSIPbUpM.js} +1 -1
- package/dist/client/assets/{markdown-ChhkSSkz.css → markdown-BpzjXclZ.css} +1 -1
- package/dist/client/assets/{mermaid.core-Bz1ouG4e.js → mermaid.core-D4_R4ZQ7.js} +4 -4
- package/dist/client/assets/{mindmap-definition-FAOFIHXS-ohtsO4nF.js → mindmap-definition-FAOFIHXS-DTiuF5JK.js} +1 -1
- package/dist/client/assets/{pegDiagram-VL7TDLO6-BmDfUXjC.js → pegDiagram-VL7TDLO6-yCIq1xSC.js} +1 -1
- package/dist/client/assets/{pieDiagram-7S7Q4E2Y-CUADuvir.js → pieDiagram-7S7Q4E2Y-B_Vgs3pz.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-BGGXYgGq.js → quadrantDiagram-CIZ2JOQS-5Ne6-Suh.js} +1 -1
- package/dist/client/assets/{railroadDiagram-AXF67PYL-CuQocJeb.js → railroadDiagram-AXF67PYL-CRQ23Ne5.js} +1 -1
- package/dist/client/assets/{render-markdown-BnNqckxy.js → render-markdown-D7BGt-zy.js} +6 -6
- package/dist/client/assets/{requirementDiagram-LRYGKXZP-7w9ufPrL.js → requirementDiagram-LRYGKXZP-Ctks1nFE.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-W5VNT64P-DWDWhnZJ.js → sankeyDiagram-W5VNT64P-D127Ar8U.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-SI44F4Z6-BQAnExHF.js → sequenceDiagram-SI44F4Z6-6hK5AS2n.js} +1 -1
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-BC2GpN9p.js → sizeCapture-X5ZJPWSS-GhdZlEoa.js} +1 -1
- package/dist/client/assets/{stateDiagram-OKZ733FA-vXwPDk5C.js → stateDiagram-OKZ733FA-u3G3OuQX.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-BSIBplQO.js +1 -0
- package/dist/client/assets/{swimlanes-SLNWSIFB-DdBBGgwS.js → swimlanes-SLNWSIFB-BIfNt9T9.js} +2 -2
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-DGRBYdxa.js +8 -0
- package/dist/client/assets/{tanstack-BEeM5REq.js → tanstack-Bsd5UOY4.js} +1 -1
- package/dist/client/assets/{timeline-definition-Z64GVDOM-CcXzq7ZH.js → timeline-definition-Z64GVDOM-CXwiFUZq.js} +1 -1
- package/dist/client/assets/{vennDiagram-T6HMQDX7-PiBQGztV.js → vennDiagram-T6HMQDX7-D9Rhew2E.js} +1 -1
- package/dist/client/assets/viewer-tabs-BW5-uV6M.js +1 -0
- package/dist/client/assets/{wardleyDiagram-T6FBY63Y-R9-CuOPS.js → wardleyDiagram-T6FBY63Y-CzCcAcBb.js} +1 -1
- package/dist/client/assets/{xychartDiagram-ELKLHX3M-CrK1rvFm.js → xychartDiagram-ELKLHX3M-BfXVbrBJ.js} +1 -1
- package/dist/client/index.html +4 -4
- package/dist/dev.mjs +4 -3
- package/dist/manifest.json +1 -1
- package/dist/server.mjs +59 -3
- package/dist/service-update.mjs +77 -0
- package/package.json +1 -1
- package/dist/client/assets/App-1nMyZ0Eq.js +0 -118
- package/dist/client/assets/EditableFileViewer-4ap_dRdR.js +0 -1
- package/dist/client/assets/HistoryView-CgKY4Sjl.js +0 -1
- package/dist/client/assets/ImageFileViewer-RAXxHOBt.js +0 -1
- package/dist/client/assets/PierreEditBoundary-YYf1awXS.js +0 -2
- package/dist/client/assets/PullRequestDiff-BWdKV4LM.js +0 -1
- package/dist/client/assets/PullRequestViewer-6MhtdrJc.js +0 -2
- package/dist/client/assets/PullRequestsView-CJy2RRm7.js +0 -1
- package/dist/client/assets/RepositoryProjectsDialog-c_ZJ0g3C.js +0 -1
- package/dist/client/assets/SearchView-D5NpA3kT.js +0 -1
- package/dist/client/assets/Viewer-u1esMhLs.js +0 -3
- package/dist/client/assets/base-ui-BxmCGIFY.js +0 -1
- package/dist/client/assets/channel-D-dDbEF9.js +0 -1
- package/dist/client/assets/checkbox-vpy6b6Uq.js +0 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-DHG_NsyB.js +0 -1
- package/dist/client/assets/classDiagram-v2-OCEON4UE-DHG_NsyB.js +0 -1
- package/dist/client/assets/index-DwuduZw_.js +0 -3
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-BA-7Q81g.js +0 -1
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-BSDBQ9JF.js +0 -8
- package/dist/client/assets/viewer-tabs-B_boC13j.js +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import process from "node:process";
|
|
3
|
-
import { r as runCli } from "./chunks/cli-
|
|
4
|
-
import "node:
|
|
2
|
+
import process$1 from "node:process";
|
|
3
|
+
import { p as parseCliArguments, C as CliUsageError, r as runCli } from "./chunks/cli-B3AR8LUd.mjs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { realpath } from "node:fs/promises";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { r as readInstallation, n as newerVersion, p as packageDirectory, O as OPEN_TIG_APP_VERSION } from "./chunks/cli-service-B939lTxw.mjs";
|
|
5
9
|
import "./server.mjs";
|
|
6
|
-
import "node:url";
|
|
7
|
-
import "node:path";
|
|
8
10
|
import "node:crypto";
|
|
9
|
-
import "node:fs/promises";
|
|
10
11
|
import "node:string_decoder";
|
|
11
12
|
import "node:util";
|
|
12
13
|
import "node:tty";
|
|
@@ -25,4 +26,54 @@ import "fs";
|
|
|
25
26
|
import "node:net";
|
|
26
27
|
import "node:http";
|
|
27
28
|
import "ws";
|
|
28
|
-
|
|
29
|
+
async function delegateToService(args, currentEntry) {
|
|
30
|
+
if (process.env.OPENTIG_DELEGATED === "1") return null;
|
|
31
|
+
let config;
|
|
32
|
+
try {
|
|
33
|
+
config = parseCliArguments(args);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (error instanceof CliUsageError) return null;
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
if (config.command === "help" || config.command === "version") {
|
|
39
|
+
const index = args.findIndex((arg) => arg === "--home" || arg.startsWith("--home="));
|
|
40
|
+
const home = index >= 0 ? args[index] === "--home" ? args[index + 1] : args[index].slice(7) : process.env.OPENTIG_HOME;
|
|
41
|
+
if (home) config.home = path.resolve(home);
|
|
42
|
+
}
|
|
43
|
+
const installed = await readInstallation(config.home);
|
|
44
|
+
if (!installed || !newerVersion(installed.version, OPEN_TIG_APP_VERSION)) return null;
|
|
45
|
+
const entry = path.join(packageDirectory(config.home, installed), "dist/bin.mjs");
|
|
46
|
+
if (await realpath(entry) === await realpath(currentEntry)) return null;
|
|
47
|
+
if (config.command === "version") {
|
|
48
|
+
process.stdout.write(`OpenTig service ${installed.version}
|
|
49
|
+
Global launcher ${OPEN_TIG_APP_VERSION}
|
|
50
|
+
`);
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const child = spawn(process.execPath, [entry, ...args], { stdio: "inherit", env: { ...process.env, OPENTIG_DELEGATED: "1" } });
|
|
55
|
+
const forward = (signal) => child.kill(signal);
|
|
56
|
+
const interrupt = () => forward("SIGINT"), terminate = () => forward("SIGTERM");
|
|
57
|
+
process.on("SIGINT", interrupt);
|
|
58
|
+
process.on("SIGTERM", terminate);
|
|
59
|
+
const clean = () => {
|
|
60
|
+
process.off("SIGINT", interrupt);
|
|
61
|
+
process.off("SIGTERM", terminate);
|
|
62
|
+
};
|
|
63
|
+
child.once("error", (error) => {
|
|
64
|
+
clean();
|
|
65
|
+
reject(error);
|
|
66
|
+
});
|
|
67
|
+
child.once("exit", (code, signal) => {
|
|
68
|
+
clean();
|
|
69
|
+
resolve(code ?? (signal === "SIGINT" ? 130 : 143));
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const args = process$1.argv.slice(2);
|
|
75
|
+
process$1.exitCode = await delegateToService(args, fileURLToPath(import.meta.url)) ?? await runCli(args);
|
|
76
|
+
} catch {
|
|
77
|
+
process$1.stderr.write("OpenTig: Could not launch the managed service version. Check the service installation.\n");
|
|
78
|
+
process$1.exitCode = 1;
|
|
79
|
+
}
|
|
@@ -3,9 +3,10 @@ import process$1 from "node:process";
|
|
|
3
3
|
import { w as writeFileAtomically, r as redactSensitiveText, n as normalizeRuntimePlatform, a as applicationName, runOpenTigServer } from "../server.mjs";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { r as readInstallation, s as systemctl, S as SERVICE_NAME, a as serviceUnitPath, p as packageDirectory, n as newerVersion, b as atomicWrite, e as execute, c as stableVersion, O as OPEN_TIG_APP_VERSION, m as manageCliService } from "./cli-service-B939lTxw.mjs";
|
|
7
|
+
import { randomUUID, createHash, randomBytes } from "node:crypto";
|
|
8
|
+
import { realpath, readFile, mkdir, rm, mkdtemp, writeFile, rename, chmod, appendFile, stat } from "node:fs/promises";
|
|
9
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
9
10
|
var QrCodeDataType = /* @__PURE__ */ ((QrCodeDataType2) => {
|
|
10
11
|
QrCodeDataType2[QrCodeDataType2["Border"] = -1] = "Border";
|
|
11
12
|
QrCodeDataType2[QrCodeDataType2["Data"] = 0] = "Data";
|
|
@@ -64,14 +65,14 @@ class QrCode {
|
|
|
64
65
|
// error correction level, data codeword bytes, and mask number.
|
|
65
66
|
// This is a low-level API that most users should not use directly.
|
|
66
67
|
// A mid-level API is the encodeSegments() function.
|
|
67
|
-
constructor(
|
|
68
|
-
this.version =
|
|
68
|
+
constructor(version, ecc, dataCodewords, msk) {
|
|
69
|
+
this.version = version;
|
|
69
70
|
this.ecc = ecc;
|
|
70
|
-
if (
|
|
71
|
+
if (version < MIN_VERSION || version > MAX_VERSION)
|
|
71
72
|
throw new RangeError("Version value out of range");
|
|
72
73
|
if (msk < -1 || msk > 7)
|
|
73
74
|
throw new RangeError("Mask value out of range");
|
|
74
|
-
this.size =
|
|
75
|
+
this.size = version * 4 + 17;
|
|
75
76
|
const row = Array.from({ length: this.size }).fill(false);
|
|
76
77
|
for (let i = 0; i < this.size; i++) {
|
|
77
78
|
this.modules.push(row.slice());
|
|
@@ -489,10 +490,10 @@ function isNumeric(text) {
|
|
|
489
490
|
function isAlphanumeric(text) {
|
|
490
491
|
return ALPHANUMERIC_REGEX.test(text);
|
|
491
492
|
}
|
|
492
|
-
function getTotalBits(segs,
|
|
493
|
+
function getTotalBits(segs, version) {
|
|
493
494
|
let result = 0;
|
|
494
495
|
for (const seg of segs) {
|
|
495
|
-
const ccbits = numCharCountBits(seg.mode,
|
|
496
|
+
const ccbits = numCharCountBits(seg.mode, version);
|
|
496
497
|
if (seg.numChars >= 1 << ccbits)
|
|
497
498
|
return Number.POSITIVE_INFINITY;
|
|
498
499
|
result += 4 + ccbits + seg.bitData.length;
|
|
@@ -568,37 +569,37 @@ function encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, b
|
|
|
568
569
|
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) {
|
|
569
570
|
throw new RangeError("Invalid value");
|
|
570
571
|
}
|
|
571
|
-
let
|
|
572
|
+
let version;
|
|
572
573
|
let dataUsedBits;
|
|
573
|
-
for (
|
|
574
|
-
const dataCapacityBits2 = getNumDataCodewords(
|
|
575
|
-
const usedBits = getTotalBits(segs,
|
|
574
|
+
for (version = minVersion; ; version++) {
|
|
575
|
+
const dataCapacityBits2 = getNumDataCodewords(version, ecl) * 8;
|
|
576
|
+
const usedBits = getTotalBits(segs, version);
|
|
576
577
|
if (usedBits <= dataCapacityBits2) {
|
|
577
578
|
dataUsedBits = usedBits;
|
|
578
579
|
break;
|
|
579
580
|
}
|
|
580
|
-
if (
|
|
581
|
+
if (version >= maxVersion)
|
|
581
582
|
throw new RangeError("Data too long");
|
|
582
583
|
}
|
|
583
584
|
for (const newEcl of [MEDIUM, QUARTILE, HIGH]) {
|
|
584
|
-
if (boostEcl && dataUsedBits <= getNumDataCodewords(
|
|
585
|
+
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
|
|
585
586
|
ecl = newEcl;
|
|
586
587
|
}
|
|
587
588
|
const bb = [];
|
|
588
589
|
for (const seg of segs) {
|
|
589
590
|
appendBits(seg.mode[0], 4, bb);
|
|
590
|
-
appendBits(seg.numChars, numCharCountBits(seg.mode,
|
|
591
|
+
appendBits(seg.numChars, numCharCountBits(seg.mode, version), bb);
|
|
591
592
|
for (const b of seg.getData())
|
|
592
593
|
bb.push(b);
|
|
593
594
|
}
|
|
594
|
-
const dataCapacityBits = getNumDataCodewords(
|
|
595
|
+
const dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
|
|
595
596
|
appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);
|
|
596
597
|
appendBits(0, (8 - bb.length % 8) % 8, bb);
|
|
597
598
|
for (let padByte = 236; bb.length < dataCapacityBits; padByte ^= 236 ^ 17)
|
|
598
599
|
appendBits(padByte, 8, bb);
|
|
599
600
|
const dataCodewords = Array.from({ length: Math.ceil(bb.length / 8) }, () => 0);
|
|
600
601
|
bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << 7 - (i & 7));
|
|
601
|
-
return new QrCode(
|
|
602
|
+
return new QrCode(version, ecl, dataCodewords, mask);
|
|
602
603
|
}
|
|
603
604
|
function encode(data, options) {
|
|
604
605
|
const {
|
|
@@ -806,8 +807,8 @@ function parseCliArguments(args, environment = process.env, currentDirectory = p
|
|
|
806
807
|
openBrowser: command === "start" && !noBrowser
|
|
807
808
|
};
|
|
808
809
|
}
|
|
809
|
-
function cliHelp(
|
|
810
|
-
return `OpenTig ${
|
|
810
|
+
function cliHelp(version) {
|
|
811
|
+
return `OpenTig ${version}
|
|
811
812
|
|
|
812
813
|
Usage:
|
|
813
814
|
opentig [options]
|
|
@@ -897,166 +898,223 @@ function resolvePath(value, currentDirectory, label) {
|
|
|
897
898
|
if (!value || value.includes("\0")) throw new CliUsageError(`Invalid ${label}.`);
|
|
898
899
|
return path.resolve(currentDirectory, value);
|
|
899
900
|
}
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
901
|
+
const DESKTOP_UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
902
|
+
const REPOSITORY = "jorgefl8/opentig";
|
|
903
|
+
const REGISTRY = "https://registry.npmjs.org";
|
|
904
|
+
const MAX_PACKAGE_BYTES = 100 * 1024 * 1024;
|
|
905
|
+
class ServiceUpdater {
|
|
906
|
+
constructor(version, backend, failedUpdate = false) {
|
|
907
|
+
this.backend = backend;
|
|
908
|
+
this.status = {
|
|
909
|
+
phase: backend ? failedUpdate ? "error" : "idle" : "unavailable",
|
|
910
|
+
currentVersion: version,
|
|
911
|
+
availableVersion: null,
|
|
912
|
+
progress: null,
|
|
913
|
+
checkedAt: null,
|
|
914
|
+
releaseUrl: null,
|
|
915
|
+
releaseNotes: null,
|
|
916
|
+
message: backend ? failedUpdate ? "The new server could not start. The previous version was restored. Check for updates to retry." : null : "Browser updates require an OpenTig Linux service. Install with opentig service install; temporary CLI and Dev instances are updated from the terminal."
|
|
917
|
+
};
|
|
909
918
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
await assertPackageBuild(packageRoot);
|
|
920
|
-
const serviceRoot = path.join(config.home, "service");
|
|
921
|
-
const target = path.join(serviceRoot, `app-${OPEN_TIG_APP_VERSION}`);
|
|
922
|
-
const temporary = path.join(serviceRoot, `.install-${process$1.pid}-${Date.now()}`);
|
|
923
|
-
await mkdir(serviceRoot, { recursive: true, mode: 448 });
|
|
924
|
-
await rm(temporary, { recursive: true, force: true });
|
|
925
|
-
try {
|
|
926
|
-
await mkdir(temporary, { recursive: true, mode: 448 });
|
|
927
|
-
await cp(path.join(packageRoot, "dist"), path.join(temporary, "dist"), { recursive: true, force: true });
|
|
928
|
-
for (const name of ["package.json", "README.md", "LICENSE", "THIRD_PARTY_NOTICES.md"]) {
|
|
929
|
-
await cp(path.join(packageRoot, name), path.join(temporary, name), { force: true });
|
|
930
|
-
}
|
|
931
|
-
await installProductionDependencies(temporary);
|
|
932
|
-
await rm(target, { recursive: true, force: true });
|
|
933
|
-
await rename(temporary, target);
|
|
934
|
-
} catch (error) {
|
|
935
|
-
await rm(temporary, { recursive: true, force: true });
|
|
936
|
-
throw error;
|
|
919
|
+
backend;
|
|
920
|
+
status;
|
|
921
|
+
offered = null;
|
|
922
|
+
timer;
|
|
923
|
+
stopped = false;
|
|
924
|
+
work = null;
|
|
925
|
+
getStatus = async () => ({ ...this.status });
|
|
926
|
+
start() {
|
|
927
|
+
if (this.backend && this.status.phase !== "error") this.schedule(1e4);
|
|
937
928
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
port: config.port,
|
|
943
|
-
home: config.home
|
|
944
|
-
});
|
|
945
|
-
await mkdir(path.dirname(unitPath), { recursive: true, mode: 448 });
|
|
946
|
-
const temporaryUnit = `${unitPath}.${process$1.pid}.tmp`;
|
|
947
|
-
await writeFile(temporaryUnit, unit, { encoding: "utf8", mode: 384 });
|
|
948
|
-
await rename(temporaryUnit, unitPath);
|
|
949
|
-
await chmod(unitPath, 384);
|
|
950
|
-
await runRequired("systemctl", ["--user", "daemon-reload"]);
|
|
951
|
-
await runRequired("systemctl", ["--user", "enable", "--now", UNIT_NAME]);
|
|
952
|
-
await runRequired("loginctl", ["enable-linger"]);
|
|
953
|
-
io.out(`OpenTig service installed and started on ${config.host}:${config.port}.`);
|
|
954
|
-
io.out(`Unit: ${unitPath}`);
|
|
955
|
-
io.out(`Pair another browser with: opentig pair --home ${config.home}`);
|
|
956
|
-
return 0;
|
|
957
|
-
}
|
|
958
|
-
async function serviceStatus(unitPath, io) {
|
|
959
|
-
try {
|
|
960
|
-
await access(unitPath);
|
|
961
|
-
} catch {
|
|
962
|
-
io.out("OpenTig service is not installed.");
|
|
963
|
-
return 1;
|
|
929
|
+
async stop() {
|
|
930
|
+
this.stopped = true;
|
|
931
|
+
clearTimeout(this.timer);
|
|
932
|
+
await this.work;
|
|
964
933
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
await rm(path.join(home, "service"), { recursive: true, force: true });
|
|
976
|
-
io.out("OpenTig service removed. Repository settings and paired sessions were kept.");
|
|
977
|
-
return 0;
|
|
978
|
-
}
|
|
979
|
-
function renderSystemdUnit(input) {
|
|
980
|
-
const args = [
|
|
981
|
-
input.nodeExecutable,
|
|
982
|
-
input.cliEntrypoint,
|
|
983
|
-
"serve",
|
|
984
|
-
"--host",
|
|
985
|
-
input.host,
|
|
986
|
-
"--port",
|
|
987
|
-
String(input.port),
|
|
988
|
-
"--home",
|
|
989
|
-
input.home
|
|
990
|
-
];
|
|
991
|
-
return `[Unit]
|
|
992
|
-
Description=OpenTig browser Git client
|
|
993
|
-
After=network.target
|
|
994
|
-
|
|
995
|
-
[Service]
|
|
996
|
-
Type=simple
|
|
997
|
-
WorkingDirectory=${systemdQuote(input.home)}
|
|
998
|
-
ExecStart=${args.map(systemdQuote).join(" ")}
|
|
999
|
-
Environment=NODE_ENV=production
|
|
1000
|
-
Restart=on-failure
|
|
1001
|
-
RestartSec=3
|
|
1002
|
-
KillSignal=SIGTERM
|
|
1003
|
-
TimeoutStopSec=10
|
|
1004
|
-
|
|
1005
|
-
[Install]
|
|
1006
|
-
WantedBy=default.target
|
|
1007
|
-
`;
|
|
1008
|
-
}
|
|
1009
|
-
function systemdQuote(value) {
|
|
1010
|
-
if (value.includes("\0") || value.includes("\r") || value.includes("\n")) throw new Error("Service paths and arguments cannot contain control characters.");
|
|
1011
|
-
return `"${value.replaceAll("%", "%%").replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
1012
|
-
}
|
|
1013
|
-
async function assertPackageBuild(packageRoot) {
|
|
1014
|
-
await Promise.all([
|
|
1015
|
-
access(path.join(packageRoot, "dist", "bin.mjs")),
|
|
1016
|
-
access(path.join(packageRoot, "dist", "client", "index.html")),
|
|
1017
|
-
readFile(path.join(packageRoot, "package.json"), "utf8")
|
|
1018
|
-
]).catch(() => {
|
|
1019
|
-
throw new Error("The OpenTig package is incomplete and cannot be installed as a service.");
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
async function findPackageRoot(modulePath) {
|
|
1023
|
-
let directory = path.dirname(modulePath);
|
|
1024
|
-
for (let depth = 0; depth < 4; depth += 1) {
|
|
934
|
+
schedule(delay2 = DESKTOP_UPDATE_CHECK_INTERVAL_MS) {
|
|
935
|
+
clearTimeout(this.timer);
|
|
936
|
+
if (!this.stopped) {
|
|
937
|
+
this.timer = setTimeout(() => void this.check(), delay2);
|
|
938
|
+
this.timer.unref();
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
check = async () => {
|
|
942
|
+
if (!this.backend || this.stopped || !["idle", "error"].includes(this.status.phase)) return this.getStatus();
|
|
943
|
+
this.status = { ...this.status, phase: "checking", message: null, progress: null };
|
|
1025
944
|
try {
|
|
1026
|
-
await
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
945
|
+
const release = await this.backend.release();
|
|
946
|
+
this.offered = release && newerVersion(release.version, this.status.currentVersion) ? release : null;
|
|
947
|
+
this.status = {
|
|
948
|
+
...this.status,
|
|
949
|
+
phase: this.offered ? "available" : "idle",
|
|
950
|
+
availableVersion: this.offered?.version ?? null,
|
|
951
|
+
releaseUrl: this.offered?.url ?? null,
|
|
952
|
+
releaseNotes: this.offered?.notes ?? null,
|
|
953
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
954
|
+
};
|
|
1031
955
|
} catch {
|
|
956
|
+
this.fail("Could not check for updates. Check your connection and try again.");
|
|
957
|
+
} finally {
|
|
958
|
+
this.schedule();
|
|
1032
959
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
960
|
+
return this.getStatus();
|
|
961
|
+
};
|
|
962
|
+
download = async () => {
|
|
963
|
+
if (!this.backend || !this.offered || this.stopped || this.status.phase !== "available") return this.getStatus();
|
|
964
|
+
this.status = { ...this.status, phase: "downloading", progress: 0, message: null };
|
|
965
|
+
this.work = this.backend.stage(this.offered, (progress) => {
|
|
966
|
+
this.status.progress = progress;
|
|
967
|
+
}).then(() => {
|
|
968
|
+
this.status = { ...this.status, phase: "ready", progress: 100 };
|
|
969
|
+
}).catch(() => this.fail("Could not prepare the update. The running service has not been replaced."));
|
|
970
|
+
return this.getStatus();
|
|
971
|
+
};
|
|
972
|
+
install = async () => {
|
|
973
|
+
if (!this.backend || !this.offered || this.stopped || this.status.phase !== "ready") return this.getStatus();
|
|
974
|
+
this.status = { ...this.status, phase: "installing", message: "Restarting the server. This browser will reconnect shortly." };
|
|
975
|
+
void this.backend.install(this.offered).catch(() => {
|
|
976
|
+
this.fail("Could not apply the update. Check the service status and try again.");
|
|
977
|
+
});
|
|
978
|
+
return this.getStatus();
|
|
979
|
+
};
|
|
980
|
+
fail(message) {
|
|
981
|
+
this.status = { ...this.status, phase: "error", progress: null, message };
|
|
1036
982
|
}
|
|
1037
|
-
throw new Error("Could not locate the installed OpenTig package.");
|
|
1038
983
|
}
|
|
1039
|
-
async function
|
|
1040
|
-
const
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
984
|
+
async function json(url) {
|
|
985
|
+
const response = await fetch(url, { headers: { Accept: "application/json" }, signal: AbortSignal.timeout(15e3) });
|
|
986
|
+
if (response.status === 404) return null;
|
|
987
|
+
if (!response.ok) throw new Error("Release metadata request failed.");
|
|
988
|
+
const text = await response.text();
|
|
989
|
+
if (text.length > 1e6) throw new Error("Release metadata is too large.");
|
|
990
|
+
return JSON.parse(text);
|
|
991
|
+
}
|
|
992
|
+
async function latestCliRelease() {
|
|
993
|
+
const release = await json(`https://api.github.com/repos/${REPOSITORY}/releases/latest`);
|
|
994
|
+
if (!release || release.draft || release.prerelease || typeof release.tag_name !== "string") return null;
|
|
995
|
+
const version = release.tag_name.replace(/^v/, "");
|
|
996
|
+
if (!stableVersion(version) || release.tag_name !== `v${version}`) return null;
|
|
997
|
+
const pkg = await json(`${REGISTRY}/@opentig%2fcli/${version}`);
|
|
998
|
+
if (!pkg) return null;
|
|
999
|
+
const dist = pkg.dist;
|
|
1000
|
+
const tarball = `${REGISTRY}/@opentig/cli/-/cli-${version}.tgz`;
|
|
1001
|
+
if (pkg.name !== "@opentig/cli" || pkg.version !== version || dist?.tarball !== tarball || typeof dist.integrity !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(dist.integrity)) throw new Error("Invalid CLI release metadata.");
|
|
1002
|
+
return {
|
|
1003
|
+
version,
|
|
1004
|
+
tarball,
|
|
1005
|
+
integrity: dist.integrity,
|
|
1006
|
+
url: `https://github.com/${REPOSITORY}/releases/tag/v${version}`,
|
|
1007
|
+
notes: typeof release.body === "string" ? release.body.slice(0, 64e3) : null
|
|
1008
|
+
};
|
|
1046
1009
|
}
|
|
1047
|
-
function
|
|
1048
|
-
|
|
1049
|
-
if (result.code !== 0) throw new Error(`${command} failed: ${result.stderr.trim() || result.stdout.trim() || `exit code ${result.code}`}`);
|
|
1050
|
-
});
|
|
1010
|
+
function verifyTarball(bytes, integrity) {
|
|
1011
|
+
if (`sha512-${createHash("sha512").update(bytes).digest("base64")}` !== integrity) throw new Error("CLI download integrity mismatch.");
|
|
1051
1012
|
}
|
|
1052
|
-
function
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1013
|
+
async function stageCliRelease(home, release, progress) {
|
|
1014
|
+
if (!stableVersion(release.version)) throw new Error("Invalid update version.");
|
|
1015
|
+
const existing = path.join(home, "service", `app-${release.version}`);
|
|
1016
|
+
try {
|
|
1017
|
+
const marker = JSON.parse(await readFile(path.join(existing, "update-integrity.json"), "utf8"));
|
|
1018
|
+
if (marker.version !== release.version || marker.integrity !== release.integrity) throw new Error("Existing candidate does not match the release.");
|
|
1019
|
+
progress(100);
|
|
1020
|
+
return;
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
if (error.code !== "ENOENT") throw error;
|
|
1023
|
+
}
|
|
1024
|
+
const temporary = await mkdtemp(path.join(home, "service/.download-"));
|
|
1025
|
+
try {
|
|
1026
|
+
const response = await fetch(release.tarball, { signal: AbortSignal.timeout(12e4), redirect: "error" });
|
|
1027
|
+
if (!response.ok || !response.body) throw new Error("CLI download failed.");
|
|
1028
|
+
const total = Number(response.headers.get("content-length"));
|
|
1029
|
+
if (total > MAX_PACKAGE_BYTES) throw new Error("CLI package too large.");
|
|
1030
|
+
let size = 0;
|
|
1031
|
+
const chunks = [];
|
|
1032
|
+
for await (const chunk of response.body) {
|
|
1033
|
+
size += chunk.length;
|
|
1034
|
+
if (size > MAX_PACKAGE_BYTES) throw new Error("CLI package too large.");
|
|
1035
|
+
chunks.push(chunk);
|
|
1036
|
+
progress(Number.isFinite(total) && total > 0 ? Math.min(85, size / total * 85) : 0);
|
|
1037
|
+
}
|
|
1038
|
+
const bytes = Buffer.concat(chunks);
|
|
1039
|
+
verifyTarball(bytes, release.integrity);
|
|
1040
|
+
const tarball = path.join(temporary, "cli.tgz");
|
|
1041
|
+
await writeFile(tarball, bytes, { mode: 384 });
|
|
1042
|
+
const target = path.join(temporary, "app");
|
|
1043
|
+
await mkdir(target);
|
|
1044
|
+
await execute("npm", ["install", "--prefix", target, "--ignore-scripts", "--omit=dev", "--no-audit", "--no-fund", "--registry", REGISTRY, tarball], { timeout: 18e4, maxBuffer: 2e6 });
|
|
1045
|
+
const pkgRoot = path.join(target, "node_modules/@opentig/cli");
|
|
1046
|
+
const pkg = JSON.parse(await readFile(path.join(pkgRoot, "package.json"), "utf8"));
|
|
1047
|
+
if (pkg.name !== "@opentig/cli" || pkg.version !== release.version) throw new Error("Installed CLI identity mismatch.");
|
|
1048
|
+
const result = await execute(process.execPath, [path.join(pkgRoot, "dist/bin.mjs"), "--version"], {
|
|
1049
|
+
timeout: 15e3,
|
|
1050
|
+
env: { ...process.env, OPENTIG_DELEGATED: "1" }
|
|
1058
1051
|
});
|
|
1059
|
-
|
|
1052
|
+
if (result.stdout.trim() !== release.version) throw new Error("New CLI cannot run.");
|
|
1053
|
+
await readFile(path.join(pkgRoot, "dist/client/index.html"));
|
|
1054
|
+
await readFile(path.join(pkgRoot, "dist/service-update.mjs"));
|
|
1055
|
+
progress(95);
|
|
1056
|
+
const destination = path.join(home, "service", `app-${release.version}`);
|
|
1057
|
+
await atomicWrite(path.join(target, "update-integrity.json"), JSON.stringify({ version: release.version, integrity: release.integrity }));
|
|
1058
|
+
await rename(target, destination);
|
|
1059
|
+
} finally {
|
|
1060
|
+
await rm(temporary, { recursive: true, force: true });
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
async function createServiceUpdater(home, version, profile, address) {
|
|
1064
|
+
let installation = null;
|
|
1065
|
+
try {
|
|
1066
|
+
if (profile === "production" && process.platform === "linux" && process.env.INVOCATION_ID) {
|
|
1067
|
+
installation = await readInstallation(home);
|
|
1068
|
+
if (!installation || installation.version !== version || installation.host !== address.host || installation.port !== address.port || await systemctl("show", SERVICE_NAME, "--property=FragmentPath", "--value") !== serviceUnitPath() || await realpath(process.argv[1]) !== await realpath(path.join(packageDirectory(home, installation), "dist/bin.mjs")) || await systemctl("show", SERVICE_NAME, "--property=MainPID", "--value") !== String(process.pid)) installation = null;
|
|
1069
|
+
}
|
|
1070
|
+
} catch {
|
|
1071
|
+
installation = null;
|
|
1072
|
+
}
|
|
1073
|
+
if (!installation) return new ServiceUpdater(version, null);
|
|
1074
|
+
const current = installation;
|
|
1075
|
+
let failedUpdate = false;
|
|
1076
|
+
try {
|
|
1077
|
+
const result = JSON.parse(await readFile(path.join(home, "service/update-result.json"), "utf8"));
|
|
1078
|
+
failedUpdate = result.success === false && result.version === version;
|
|
1079
|
+
} catch {
|
|
1080
|
+
}
|
|
1081
|
+
const updater = new ServiceUpdater(version, {
|
|
1082
|
+
release: latestCliRelease,
|
|
1083
|
+
stage: (release, progress) => stageCliRelease(home, release, progress),
|
|
1084
|
+
install: async (release) => {
|
|
1085
|
+
const lock = path.join(home, "service/update-lock");
|
|
1086
|
+
await mkdir(lock, { mode: 448 });
|
|
1087
|
+
const unit = `opentig-update-${randomUUID()}`;
|
|
1088
|
+
try {
|
|
1089
|
+
const next = { ...current, version: release.version, layout: "npm" };
|
|
1090
|
+
const previousUnit = await readFile(serviceUnitPath(), "utf8");
|
|
1091
|
+
await atomicWrite(path.join(lock, "plan.json"), JSON.stringify({ home, current, next, previousUnit, integrity: release.integrity }));
|
|
1092
|
+
await execute("systemd-run", [
|
|
1093
|
+
"--user",
|
|
1094
|
+
"--collect",
|
|
1095
|
+
"--unit",
|
|
1096
|
+
unit,
|
|
1097
|
+
"--property=Type=exec",
|
|
1098
|
+
process.execPath,
|
|
1099
|
+
path.join(packageDirectory(home, current), "dist/service-update.mjs"),
|
|
1100
|
+
home
|
|
1101
|
+
], { timeout: 15e3 });
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
await rm(lock, { recursive: true, force: true });
|
|
1104
|
+
throw error;
|
|
1105
|
+
}
|
|
1106
|
+
for (let attempt = 0; attempt < 120; attempt++) {
|
|
1107
|
+
await setTimeout$1(1e3);
|
|
1108
|
+
const state = await systemctl("show", unit, "--property=ActiveState", "--value").catch(() => "inactive");
|
|
1109
|
+
if (!["active", "activating", "deactivating"].includes(state)) {
|
|
1110
|
+
await rm(lock, { recursive: true, force: true });
|
|
1111
|
+
throw new Error("Update worker exited without replacing the server.");
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
throw new Error("Update worker did not restart the service.");
|
|
1115
|
+
}
|
|
1116
|
+
}, failedUpdate);
|
|
1117
|
+
return updater;
|
|
1060
1118
|
}
|
|
1061
1119
|
const RUNTIME_STATE_VERSION = 1;
|
|
1062
1120
|
function resolveCliPaths(home) {
|
|
@@ -1114,7 +1172,7 @@ async function readRuntimeState(filePath) {
|
|
|
1114
1172
|
try {
|
|
1115
1173
|
value = JSON.parse(await readFile(filePath, "utf8"));
|
|
1116
1174
|
} catch (error) {
|
|
1117
|
-
if (error.code === "ENOENT") throw new Error("No running OpenTig server was found for this home.");
|
|
1175
|
+
if (error.code === "ENOENT") throw new Error("No running OpenTig server was found for this home.", { cause: error });
|
|
1118
1176
|
throw new Error("OpenTig runtime state is unreadable.", { cause: error });
|
|
1119
1177
|
}
|
|
1120
1178
|
if (!isRuntimeState(value)) throw new Error("OpenTig runtime state is invalid.");
|
|
@@ -1219,10 +1277,12 @@ async function startCliServer(config, io, profile) {
|
|
|
1219
1277
|
const adminToken = await loadOrCreateAdminToken(paths.adminToken);
|
|
1220
1278
|
const instanceId = newInstanceId();
|
|
1221
1279
|
const log = new CliServerLog(paths.serverLog);
|
|
1280
|
+
const updates = await createServiceUpdater(config.home, OPEN_TIG_APP_VERSION, profile, config);
|
|
1222
1281
|
let server = null;
|
|
1223
1282
|
try {
|
|
1224
1283
|
server = await startOnConfiguredPort({
|
|
1225
1284
|
appVersion: OPEN_TIG_APP_VERSION,
|
|
1285
|
+
updates,
|
|
1226
1286
|
profile,
|
|
1227
1287
|
auth: { consumeDesktopSecret: () => false },
|
|
1228
1288
|
settingsPath: paths.settings,
|
|
@@ -1261,11 +1321,14 @@ async function startCliServer(config, io, profile) {
|
|
|
1261
1321
|
io.error("Could not open the system browser. Open the one-time pairing link shown above manually.");
|
|
1262
1322
|
});
|
|
1263
1323
|
}
|
|
1324
|
+
updates.start();
|
|
1264
1325
|
return await waitForShutdown(server, async () => {
|
|
1326
|
+
await updates.stop();
|
|
1265
1327
|
await clearRuntimeState(paths.runtimeState, instanceId);
|
|
1266
1328
|
await log.close();
|
|
1267
1329
|
}, io);
|
|
1268
1330
|
} catch (error) {
|
|
1331
|
+
await updates.stop();
|
|
1269
1332
|
if (server) await server.close().catch(() => void 0);
|
|
1270
1333
|
await clearRuntimeState(paths.runtimeState, instanceId).catch(() => void 0);
|
|
1271
1334
|
await log.close();
|
|
@@ -1403,5 +1466,6 @@ function assertGitAvailable() {
|
|
|
1403
1466
|
}
|
|
1404
1467
|
export {
|
|
1405
1468
|
CliUsageError as C,
|
|
1469
|
+
parseCliArguments as p,
|
|
1406
1470
|
runCli as r
|
|
1407
1471
|
};
|