@hermespilot/link 0.2.0 → 0.2.2
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.
|
@@ -3587,7 +3587,7 @@ async function listCronOutputFiles(profileName, jobId) {
|
|
|
3587
3587
|
mtimeMs: fileStat.mtimeMs
|
|
3588
3588
|
});
|
|
3589
3589
|
}
|
|
3590
|
-
return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path:
|
|
3590
|
+
return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path: path23, mtime }) => ({ path: path23, mtime }));
|
|
3591
3591
|
}
|
|
3592
3592
|
async function readCronOutput(outputPath) {
|
|
3593
3593
|
const content = await readFile3(outputPath, "utf8");
|
|
@@ -4677,7 +4677,7 @@ import os2 from "os";
|
|
|
4677
4677
|
import path7 from "path";
|
|
4678
4678
|
|
|
4679
4679
|
// src/constants.ts
|
|
4680
|
-
var LINK_VERSION = "0.2.
|
|
4680
|
+
var LINK_VERSION = "0.2.2";
|
|
4681
4681
|
var LINK_COMMAND = "hermeslink";
|
|
4682
4682
|
var LINK_DEFAULT_PORT = 52379;
|
|
4683
4683
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -7963,10 +7963,10 @@ async function cancelHermesRun(runId, options = {}) {
|
|
|
7963
7963
|
);
|
|
7964
7964
|
}
|
|
7965
7965
|
}
|
|
7966
|
-
async function callHermesApi(
|
|
7966
|
+
async function callHermesApi(path23, init, options) {
|
|
7967
7967
|
const method = init.method ?? "GET";
|
|
7968
7968
|
const startedAt = Date.now();
|
|
7969
|
-
void options.logger?.debug("hermes_api_request_started", { method, path:
|
|
7969
|
+
void options.logger?.debug("hermes_api_request_started", { method, path: path23 });
|
|
7970
7970
|
const availability = await ensureHermesApiServerAvailable({
|
|
7971
7971
|
fetchImpl: options.fetchImpl,
|
|
7972
7972
|
logger: options.logger,
|
|
@@ -7974,21 +7974,21 @@ async function callHermesApi(path22, init, options) {
|
|
|
7974
7974
|
});
|
|
7975
7975
|
let config = availability.configResult.apiServer;
|
|
7976
7976
|
const fetcher = options.fetchImpl ?? fetch;
|
|
7977
|
-
const request = () => fetchHermesApi(fetcher, config,
|
|
7977
|
+
const request = () => fetchHermesApi(fetcher, config, path23, init, options);
|
|
7978
7978
|
let response;
|
|
7979
7979
|
try {
|
|
7980
7980
|
response = await request();
|
|
7981
7981
|
} catch (error) {
|
|
7982
|
-
logHermesApiError(options.logger, method,
|
|
7982
|
+
logHermesApiError(options.logger, method, path23, startedAt, error);
|
|
7983
7983
|
throw error;
|
|
7984
7984
|
}
|
|
7985
7985
|
if (response.status !== 401) {
|
|
7986
|
-
logHermesApiResponse(options.logger, method,
|
|
7986
|
+
logHermesApiResponse(options.logger, method, path23, startedAt, response);
|
|
7987
7987
|
return response;
|
|
7988
7988
|
}
|
|
7989
7989
|
void options.logger?.warn("hermes_api_request_retrying_after_401", {
|
|
7990
7990
|
method,
|
|
7991
|
-
path:
|
|
7991
|
+
path: path23,
|
|
7992
7992
|
duration_ms: Date.now() - startedAt
|
|
7993
7993
|
});
|
|
7994
7994
|
const refreshedAvailability = await ensureHermesApiServerAvailable({
|
|
@@ -8001,20 +8001,20 @@ async function callHermesApi(path22, init, options) {
|
|
|
8001
8001
|
try {
|
|
8002
8002
|
response = await request();
|
|
8003
8003
|
} catch (error) {
|
|
8004
|
-
logHermesApiError(options.logger, method,
|
|
8004
|
+
logHermesApiError(options.logger, method, path23, startedAt, error);
|
|
8005
8005
|
throw error;
|
|
8006
8006
|
}
|
|
8007
|
-
logHermesApiResponse(options.logger, method,
|
|
8007
|
+
logHermesApiResponse(options.logger, method, path23, startedAt, response);
|
|
8008
8008
|
return response;
|
|
8009
8009
|
}
|
|
8010
|
-
async function fetchHermesApi(fetcher, config,
|
|
8010
|
+
async function fetchHermesApi(fetcher, config, path23, init, options) {
|
|
8011
8011
|
const headers = new Headers(init.headers);
|
|
8012
8012
|
headers.set("accept", headers.get("accept") ?? "application/json");
|
|
8013
8013
|
if (config.key) {
|
|
8014
8014
|
headers.set("x-api-key", config.key);
|
|
8015
8015
|
headers.set("authorization", `Bearer ${config.key}`);
|
|
8016
8016
|
}
|
|
8017
|
-
return await fetcher(`http://127.0.0.1:${config.port}${
|
|
8017
|
+
return await fetcher(`http://127.0.0.1:${config.port}${path23}`, {
|
|
8018
8018
|
...init,
|
|
8019
8019
|
headers
|
|
8020
8020
|
}).catch((error) => {
|
|
@@ -8022,7 +8022,7 @@ async function fetchHermesApi(fetcher, config, path22, init, options) {
|
|
|
8022
8022
|
throw error;
|
|
8023
8023
|
}
|
|
8024
8024
|
void options.logger?.warn("hermes_api_server_connect_failed", {
|
|
8025
|
-
path:
|
|
8025
|
+
path: path23,
|
|
8026
8026
|
port: config.port ?? null,
|
|
8027
8027
|
error: error instanceof Error ? error.message : String(error)
|
|
8028
8028
|
});
|
|
@@ -8033,10 +8033,10 @@ async function fetchHermesApi(fetcher, config, path22, init, options) {
|
|
|
8033
8033
|
);
|
|
8034
8034
|
});
|
|
8035
8035
|
}
|
|
8036
|
-
function logHermesApiResponse(logger, method,
|
|
8036
|
+
function logHermesApiResponse(logger, method, path23, startedAt, response) {
|
|
8037
8037
|
const fields = {
|
|
8038
8038
|
method,
|
|
8039
|
-
path:
|
|
8039
|
+
path: path23,
|
|
8040
8040
|
status: response.status,
|
|
8041
8041
|
duration_ms: Date.now() - startedAt
|
|
8042
8042
|
};
|
|
@@ -8056,10 +8056,10 @@ async function logHermesApiFailureResponse(logger, fields, response) {
|
|
|
8056
8056
|
...upstreamError ? { upstream_error: upstreamError } : {}
|
|
8057
8057
|
});
|
|
8058
8058
|
}
|
|
8059
|
-
function logHermesApiError(logger, method,
|
|
8059
|
+
function logHermesApiError(logger, method, path23, startedAt, error) {
|
|
8060
8060
|
void logger?.warn("hermes_api_request_failed", {
|
|
8061
8061
|
method,
|
|
8062
|
-
path:
|
|
8062
|
+
path: path23,
|
|
8063
8063
|
duration_ms: Date.now() - startedAt,
|
|
8064
8064
|
...error instanceof LinkHttpError ? { status: error.status, code: error.code } : {},
|
|
8065
8065
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -15882,10 +15882,535 @@ function readString14(payload, key) {
|
|
|
15882
15882
|
}
|
|
15883
15883
|
|
|
15884
15884
|
// src/link/updates.ts
|
|
15885
|
-
import { spawn as
|
|
15885
|
+
import { spawn as spawn5 } from "child_process";
|
|
15886
15886
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
15887
|
-
import { mkdir as
|
|
15887
|
+
import { mkdir as mkdir16, readFile as readFile16, rm as rm10 } from "fs/promises";
|
|
15888
|
+
import path21 from "path";
|
|
15889
|
+
|
|
15890
|
+
// src/daemon/process.ts
|
|
15891
|
+
import { spawn as spawn4 } from "child_process";
|
|
15892
|
+
import { mkdir as mkdir15, readFile as readFile15, rm as rm9 } from "fs/promises";
|
|
15888
15893
|
import path20 from "path";
|
|
15894
|
+
|
|
15895
|
+
// src/daemon/service.ts
|
|
15896
|
+
import { createServer } from "http";
|
|
15897
|
+
import { mkdir as mkdir14, rm as rm8, writeFile as writeFile7 } from "fs/promises";
|
|
15898
|
+
|
|
15899
|
+
// src/relay/control-client.ts
|
|
15900
|
+
import WebSocket from "ws";
|
|
15901
|
+
function connectRelayControl(options) {
|
|
15902
|
+
const wsUrl = new URL(`${options.relayBaseUrl.replace(/\/+$/u, "")}/api/v1/relay/link/connect`);
|
|
15903
|
+
wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
15904
|
+
wsUrl.searchParams.set("link_id", options.linkId);
|
|
15905
|
+
const maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
|
|
15906
|
+
const backoffBaseMs = options.backoffBaseMs ?? 1e3;
|
|
15907
|
+
const backoffMaxMs = options.backoffMaxMs ?? 3e4;
|
|
15908
|
+
let reconnectAttempts = 0;
|
|
15909
|
+
let closedByUser = false;
|
|
15910
|
+
let socket = null;
|
|
15911
|
+
let retryTimer = null;
|
|
15912
|
+
let abortControllers = /* @__PURE__ */ new Map();
|
|
15913
|
+
let fatalRelayRejection = null;
|
|
15914
|
+
const connect = () => {
|
|
15915
|
+
options.onStatus?.({ state: "connecting", attempt: reconnectAttempts });
|
|
15916
|
+
fatalRelayRejection = null;
|
|
15917
|
+
socket = new WebSocket(wsUrl, {
|
|
15918
|
+
headers: {
|
|
15919
|
+
"x-hermes-link-version": LINK_VERSION
|
|
15920
|
+
}
|
|
15921
|
+
});
|
|
15922
|
+
socket.on("open", () => {
|
|
15923
|
+
reconnectAttempts = 0;
|
|
15924
|
+
options.onStatus?.({ state: "connected", attempt: reconnectAttempts });
|
|
15925
|
+
});
|
|
15926
|
+
socket.on("message", (raw) => {
|
|
15927
|
+
if (!socket || typeof raw !== "string" && !Buffer.isBuffer(raw)) {
|
|
15928
|
+
return;
|
|
15929
|
+
}
|
|
15930
|
+
void handleFrame(socket, String(raw), options.localPort, abortControllers).catch((error) => {
|
|
15931
|
+
const message = error instanceof Error ? error.message : "Relay request failed";
|
|
15932
|
+
socket?.send(JSON.stringify({ type: "http.error", id: "unknown", status: 502, message }));
|
|
15933
|
+
});
|
|
15934
|
+
});
|
|
15935
|
+
socket.on("error", (error) => {
|
|
15936
|
+
const message = error instanceof Error ? error.message : "Relay websocket error";
|
|
15937
|
+
fatalRelayRejection = resolveFatalRelayRejection(message);
|
|
15938
|
+
options.onStatus?.({
|
|
15939
|
+
state: "disconnected",
|
|
15940
|
+
attempt: reconnectAttempts,
|
|
15941
|
+
message: fatalRelayRejection ?? message
|
|
15942
|
+
});
|
|
15943
|
+
});
|
|
15944
|
+
socket.on("close", () => {
|
|
15945
|
+
abortAll(abortControllers);
|
|
15946
|
+
abortControllers = /* @__PURE__ */ new Map();
|
|
15947
|
+
if (fatalRelayRejection) {
|
|
15948
|
+
options.onStatus?.({
|
|
15949
|
+
state: "failed",
|
|
15950
|
+
attempt: reconnectAttempts,
|
|
15951
|
+
message: fatalRelayRejection
|
|
15952
|
+
});
|
|
15953
|
+
return;
|
|
15954
|
+
}
|
|
15955
|
+
if (closedByUser) {
|
|
15956
|
+
options.onStatus?.({ state: "disconnected", attempt: reconnectAttempts });
|
|
15957
|
+
return;
|
|
15958
|
+
}
|
|
15959
|
+
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
15960
|
+
options.onStatus?.({ state: "failed", attempt: reconnectAttempts, message: "Relay reconnect attempts exhausted" });
|
|
15961
|
+
return;
|
|
15962
|
+
}
|
|
15963
|
+
reconnectAttempts += 1;
|
|
15964
|
+
const delay2 = computeBackoffMs(reconnectAttempts, backoffBaseMs, backoffMaxMs);
|
|
15965
|
+
options.onStatus?.({ state: "retrying", attempt: reconnectAttempts, message: `Retrying in ${delay2}ms` });
|
|
15966
|
+
retryTimer = setTimeout(connect, delay2);
|
|
15967
|
+
retryTimer.unref?.();
|
|
15968
|
+
});
|
|
15969
|
+
};
|
|
15970
|
+
connect();
|
|
15971
|
+
return {
|
|
15972
|
+
close() {
|
|
15973
|
+
closedByUser = true;
|
|
15974
|
+
if (retryTimer) {
|
|
15975
|
+
clearTimeout(retryTimer);
|
|
15976
|
+
retryTimer = null;
|
|
15977
|
+
}
|
|
15978
|
+
abortAll(abortControllers);
|
|
15979
|
+
socket?.terminate();
|
|
15980
|
+
}
|
|
15981
|
+
};
|
|
15982
|
+
}
|
|
15983
|
+
function resolveFatalRelayRejection(message) {
|
|
15984
|
+
if (!/Unexpected server response:\s*(400|401|403|426)\b/u.test(message)) {
|
|
15985
|
+
return null;
|
|
15986
|
+
}
|
|
15987
|
+
return "Relay refused the Hermes Link connection. Check Link version and pairing state before retrying.";
|
|
15988
|
+
}
|
|
15989
|
+
function abortAll(abortControllers) {
|
|
15990
|
+
for (const controller of abortControllers.values()) {
|
|
15991
|
+
controller.abort();
|
|
15992
|
+
}
|
|
15993
|
+
abortControllers.clear();
|
|
15994
|
+
}
|
|
15995
|
+
function computeBackoffMs(attempt, baseMs, maxMs) {
|
|
15996
|
+
const exponential = Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt - 1));
|
|
15997
|
+
const jitter = Math.floor(Math.random() * Math.min(1e3, exponential * 0.2));
|
|
15998
|
+
return exponential + jitter;
|
|
15999
|
+
}
|
|
16000
|
+
async function handleFrame(socket, raw, localPort, abortControllers) {
|
|
16001
|
+
const frame = JSON.parse(raw);
|
|
16002
|
+
if (frame.type === "http.cancel") {
|
|
16003
|
+
abortControllers.get(frame.id)?.abort();
|
|
16004
|
+
abortControllers.delete(frame.id);
|
|
16005
|
+
return;
|
|
16006
|
+
}
|
|
16007
|
+
if (frame.type !== "http.request") {
|
|
16008
|
+
return;
|
|
16009
|
+
}
|
|
16010
|
+
const abortController = new AbortController();
|
|
16011
|
+
abortControllers.set(frame.id, abortController);
|
|
16012
|
+
try {
|
|
16013
|
+
const response = await fetch(`http://127.0.0.1:${localPort}${frame.path}`, {
|
|
16014
|
+
method: frame.method,
|
|
16015
|
+
headers: frame.headers ?? {},
|
|
16016
|
+
body: frame.bodyBase64 ? Buffer.from(frame.bodyBase64, "base64") : void 0,
|
|
16017
|
+
signal: abortController.signal
|
|
16018
|
+
});
|
|
16019
|
+
const headers = Object.fromEntries(response.headers.entries());
|
|
16020
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
16021
|
+
if (response.body && contentType.includes("text/event-stream")) {
|
|
16022
|
+
socket.send(JSON.stringify({ type: "http.stream.start", id: frame.id, status: response.status, headers }));
|
|
16023
|
+
const reader = response.body.getReader();
|
|
16024
|
+
while (true) {
|
|
16025
|
+
const next = await reader.read();
|
|
16026
|
+
if (next.done) {
|
|
16027
|
+
break;
|
|
16028
|
+
}
|
|
16029
|
+
socket.send(JSON.stringify({ type: "http.stream.chunk", id: frame.id, bodyBase64: Buffer.from(next.value).toString("base64") }));
|
|
16030
|
+
}
|
|
16031
|
+
socket.send(JSON.stringify({ type: "http.stream.end", id: frame.id }));
|
|
16032
|
+
return;
|
|
16033
|
+
}
|
|
16034
|
+
const body = Buffer.from(await response.arrayBuffer()).toString("base64");
|
|
16035
|
+
socket.send(JSON.stringify({ type: "http.response", id: frame.id, status: response.status, headers, bodyBase64: body }));
|
|
16036
|
+
} catch (error) {
|
|
16037
|
+
const message = error instanceof Error ? error.message : "Relay request failed";
|
|
16038
|
+
socket.send(JSON.stringify({ type: "http.error", id: frame.id, status: 502, message }));
|
|
16039
|
+
} finally {
|
|
16040
|
+
abortControllers.delete(frame.id);
|
|
16041
|
+
}
|
|
16042
|
+
}
|
|
16043
|
+
|
|
16044
|
+
// src/daemon/scheduler.ts
|
|
16045
|
+
function startCronDeliveryScheduler(options) {
|
|
16046
|
+
let running = false;
|
|
16047
|
+
const syncCronDeliveries = async () => {
|
|
16048
|
+
if (running) {
|
|
16049
|
+
return;
|
|
16050
|
+
}
|
|
16051
|
+
running = true;
|
|
16052
|
+
try {
|
|
16053
|
+
await syncHermesLinkCronDeliveries(
|
|
16054
|
+
options.paths,
|
|
16055
|
+
options.conversations,
|
|
16056
|
+
options.logger
|
|
16057
|
+
);
|
|
16058
|
+
} catch (error) {
|
|
16059
|
+
void options.logger.warn("cron_link_delivery_sync_failed", {
|
|
16060
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16061
|
+
});
|
|
16062
|
+
} finally {
|
|
16063
|
+
running = false;
|
|
16064
|
+
}
|
|
16065
|
+
};
|
|
16066
|
+
const timer = setInterval(() => {
|
|
16067
|
+
void syncCronDeliveries();
|
|
16068
|
+
}, options.intervalMs ?? 3e4);
|
|
16069
|
+
timer.unref?.();
|
|
16070
|
+
return {
|
|
16071
|
+
close() {
|
|
16072
|
+
clearInterval(timer);
|
|
16073
|
+
}
|
|
16074
|
+
};
|
|
16075
|
+
}
|
|
16076
|
+
|
|
16077
|
+
// src/daemon/service.ts
|
|
16078
|
+
async function startLinkService(options = {}) {
|
|
16079
|
+
const paths = options.paths ?? resolveRuntimePaths();
|
|
16080
|
+
const logger = createFileLogger({ paths });
|
|
16081
|
+
const [identity, config] = await Promise.all([loadIdentity(paths), loadConfig(paths)]);
|
|
16082
|
+
await logger.info("service_starting", {
|
|
16083
|
+
port: config.port,
|
|
16084
|
+
mode: identity?.link_id ? "paired" : "local-only"
|
|
16085
|
+
});
|
|
16086
|
+
const migration = await migrateLinkDatabase(paths);
|
|
16087
|
+
if (migration.appliedVersions.length > 0) {
|
|
16088
|
+
await logger.info("database_migrated", {
|
|
16089
|
+
database_file: migration.databaseFile,
|
|
16090
|
+
applied_versions: migration.appliedVersions,
|
|
16091
|
+
current_version: migration.currentVersion
|
|
16092
|
+
});
|
|
16093
|
+
}
|
|
16094
|
+
const conversations = new ConversationService(paths, logger);
|
|
16095
|
+
await conversations.rebuildStatisticsIndex();
|
|
16096
|
+
const app = await createApp({
|
|
16097
|
+
paths,
|
|
16098
|
+
logger,
|
|
16099
|
+
conversations,
|
|
16100
|
+
onPairingClaimed: options.onPairingClaimed
|
|
16101
|
+
});
|
|
16102
|
+
const server = createServer(app.callback());
|
|
16103
|
+
try {
|
|
16104
|
+
await listenServer(server, config.port);
|
|
16105
|
+
} catch (error) {
|
|
16106
|
+
await logger.error("service_start_failed", {
|
|
16107
|
+
port: config.port,
|
|
16108
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16109
|
+
});
|
|
16110
|
+
await logger.flush();
|
|
16111
|
+
throw error;
|
|
16112
|
+
}
|
|
16113
|
+
server.on("error", (error) => {
|
|
16114
|
+
void logger.error("service_error", { error: error.message });
|
|
16115
|
+
});
|
|
16116
|
+
void logger.info("service_started", {
|
|
16117
|
+
port: config.port,
|
|
16118
|
+
link_id: identity?.link_id ?? null
|
|
16119
|
+
});
|
|
16120
|
+
const scheduler = startCronDeliveryScheduler({
|
|
16121
|
+
paths,
|
|
16122
|
+
conversations,
|
|
16123
|
+
logger
|
|
16124
|
+
});
|
|
16125
|
+
let relay = null;
|
|
16126
|
+
if (identity?.link_id) {
|
|
16127
|
+
relay = connectRelayControl({
|
|
16128
|
+
relayBaseUrl: config.relayBaseUrl,
|
|
16129
|
+
linkId: identity.link_id,
|
|
16130
|
+
localPort: config.port,
|
|
16131
|
+
maxReconnectAttempts: options.relayMaxReconnectAttempts ?? 5,
|
|
16132
|
+
backoffBaseMs: 1e3,
|
|
16133
|
+
backoffMaxMs: 3e4,
|
|
16134
|
+
onStatus: (status) => {
|
|
16135
|
+
void logger.info("relay_status", status);
|
|
16136
|
+
}
|
|
16137
|
+
});
|
|
16138
|
+
} else {
|
|
16139
|
+
void logger.info("relay_skipped", { reason: "link_not_paired" });
|
|
16140
|
+
}
|
|
16141
|
+
if (options.writePidFile) {
|
|
16142
|
+
await writePidFile(paths);
|
|
16143
|
+
}
|
|
16144
|
+
return {
|
|
16145
|
+
async close() {
|
|
16146
|
+
scheduler.close();
|
|
16147
|
+
relay?.close();
|
|
16148
|
+
await closeServer(server);
|
|
16149
|
+
await logger.info("service_stopped");
|
|
16150
|
+
await logger.flush();
|
|
16151
|
+
if (options.writePidFile) {
|
|
16152
|
+
await rm8(pidFilePath(paths), { force: true }).catch(() => void 0);
|
|
16153
|
+
}
|
|
16154
|
+
}
|
|
16155
|
+
};
|
|
16156
|
+
}
|
|
16157
|
+
function pidFilePath(paths = resolveRuntimePaths()) {
|
|
16158
|
+
return `${paths.runDir}/hermeslink.pid`;
|
|
16159
|
+
}
|
|
16160
|
+
async function writePidFile(paths) {
|
|
16161
|
+
await mkdir14(paths.runDir, { recursive: true, mode: 448 });
|
|
16162
|
+
await writeFile7(pidFilePath(paths), `${process.pid}
|
|
16163
|
+
`, { mode: 384 });
|
|
16164
|
+
}
|
|
16165
|
+
async function closeServer(server) {
|
|
16166
|
+
await new Promise((resolve, reject) => {
|
|
16167
|
+
let settled = false;
|
|
16168
|
+
let forceCloseTimer;
|
|
16169
|
+
let timeoutTimer;
|
|
16170
|
+
const settle = (error) => {
|
|
16171
|
+
if (settled) {
|
|
16172
|
+
return;
|
|
16173
|
+
}
|
|
16174
|
+
settled = true;
|
|
16175
|
+
clearTimeout(forceCloseTimer);
|
|
16176
|
+
clearTimeout(timeoutTimer);
|
|
16177
|
+
if (error) {
|
|
16178
|
+
reject(error);
|
|
16179
|
+
return;
|
|
16180
|
+
}
|
|
16181
|
+
resolve();
|
|
16182
|
+
};
|
|
16183
|
+
forceCloseTimer = setTimeout(() => {
|
|
16184
|
+
server.closeIdleConnections?.();
|
|
16185
|
+
server.closeAllConnections?.();
|
|
16186
|
+
}, 250);
|
|
16187
|
+
timeoutTimer = setTimeout(() => {
|
|
16188
|
+
server.closeAllConnections?.();
|
|
16189
|
+
settle();
|
|
16190
|
+
}, 5e3);
|
|
16191
|
+
server.close((error) => {
|
|
16192
|
+
if (error) {
|
|
16193
|
+
settle(error);
|
|
16194
|
+
return;
|
|
16195
|
+
}
|
|
16196
|
+
settle();
|
|
16197
|
+
});
|
|
16198
|
+
server.closeIdleConnections?.();
|
|
16199
|
+
});
|
|
16200
|
+
}
|
|
16201
|
+
async function listenServer(server, port) {
|
|
16202
|
+
await new Promise((resolve, reject) => {
|
|
16203
|
+
const cleanup = () => {
|
|
16204
|
+
server.off("error", onError);
|
|
16205
|
+
server.off("listening", onListening);
|
|
16206
|
+
};
|
|
16207
|
+
const onError = (error) => {
|
|
16208
|
+
cleanup();
|
|
16209
|
+
reject(error);
|
|
16210
|
+
};
|
|
16211
|
+
const onListening = () => {
|
|
16212
|
+
cleanup();
|
|
16213
|
+
resolve();
|
|
16214
|
+
};
|
|
16215
|
+
server.once("error", onError);
|
|
16216
|
+
server.once("listening", onListening);
|
|
16217
|
+
server.listen(port);
|
|
16218
|
+
});
|
|
16219
|
+
}
|
|
16220
|
+
|
|
16221
|
+
// src/daemon/process.ts
|
|
16222
|
+
async function startDaemonProcess(paths = resolveRuntimePaths()) {
|
|
16223
|
+
const config = await loadConfig(paths);
|
|
16224
|
+
let status = await getDaemonStatus(paths);
|
|
16225
|
+
if (status.running) {
|
|
16226
|
+
const probe = await probeLocalLinkService({ port: config.port, timeoutMs: 500 });
|
|
16227
|
+
if (probe.reachable) {
|
|
16228
|
+
return status;
|
|
16229
|
+
}
|
|
16230
|
+
await stopDaemonProcess(paths);
|
|
16231
|
+
status = await getDaemonStatus(paths);
|
|
16232
|
+
if (status.running) {
|
|
16233
|
+
return status;
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
await mkdir15(paths.logsDir, { recursive: true, mode: 448 });
|
|
16237
|
+
await mkdir15(paths.runDir, { recursive: true, mode: 448 });
|
|
16238
|
+
const scriptPath = currentCliScriptPath();
|
|
16239
|
+
const child = spawn4(process.execPath, [scriptPath, "daemon-supervisor"], {
|
|
16240
|
+
detached: true,
|
|
16241
|
+
stdio: "ignore",
|
|
16242
|
+
env: process.env
|
|
16243
|
+
});
|
|
16244
|
+
child.unref();
|
|
16245
|
+
for (let index = 0; index < 12; index += 1) {
|
|
16246
|
+
await wait(250);
|
|
16247
|
+
const next = await getDaemonStatus(paths);
|
|
16248
|
+
if (next.running && (await probeLocalLinkService({ port: config.port, timeoutMs: 500 })).reachable) {
|
|
16249
|
+
return next;
|
|
16250
|
+
}
|
|
16251
|
+
}
|
|
16252
|
+
return await getDaemonStatus(paths);
|
|
16253
|
+
}
|
|
16254
|
+
async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
|
|
16255
|
+
await mkdir15(paths.logsDir, { recursive: true, mode: 448 });
|
|
16256
|
+
const log = createRotatingTextLogWriter({
|
|
16257
|
+
paths,
|
|
16258
|
+
fileName: path20.basename(daemonLogFile(paths))
|
|
16259
|
+
});
|
|
16260
|
+
const scriptPath = currentCliScriptPath();
|
|
16261
|
+
const child = spawn4(process.execPath, [scriptPath, "daemon", "--foreground"], {
|
|
16262
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16263
|
+
env: process.env
|
|
16264
|
+
});
|
|
16265
|
+
const write = (chunk) => {
|
|
16266
|
+
void log.write(chunk);
|
|
16267
|
+
};
|
|
16268
|
+
write(`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon supervisor started
|
|
16269
|
+
`);
|
|
16270
|
+
child.stdout?.on("data", write);
|
|
16271
|
+
child.stderr?.on("data", write);
|
|
16272
|
+
const forwardStop = () => {
|
|
16273
|
+
if (child.pid && isProcessAlive3(child.pid)) {
|
|
16274
|
+
child.kill("SIGTERM");
|
|
16275
|
+
}
|
|
16276
|
+
};
|
|
16277
|
+
process.once("SIGINT", forwardStop);
|
|
16278
|
+
process.once("SIGTERM", forwardStop);
|
|
16279
|
+
const result = await new Promise((resolve, reject) => {
|
|
16280
|
+
child.once("error", reject);
|
|
16281
|
+
child.once("exit", (code, signal) => resolve({ code, signal }));
|
|
16282
|
+
}).catch((error) => {
|
|
16283
|
+
write(`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon supervisor failed: ${error instanceof Error ? error.message : String(error)}
|
|
16284
|
+
`);
|
|
16285
|
+
return { code: 1, signal: null };
|
|
16286
|
+
});
|
|
16287
|
+
process.off("SIGINT", forwardStop);
|
|
16288
|
+
process.off("SIGTERM", forwardStop);
|
|
16289
|
+
write(
|
|
16290
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon supervisor stopped code=${result.code ?? "null"} signal=${result.signal ?? "null"}
|
|
16291
|
+
`
|
|
16292
|
+
);
|
|
16293
|
+
await log.flush();
|
|
16294
|
+
return result.code ?? (result.signal ? 0 : 1);
|
|
16295
|
+
}
|
|
16296
|
+
async function probeLocalLinkService(options) {
|
|
16297
|
+
const unreachable = {
|
|
16298
|
+
reachable: false,
|
|
16299
|
+
reusable: false,
|
|
16300
|
+
linkId: null,
|
|
16301
|
+
version: null
|
|
16302
|
+
};
|
|
16303
|
+
let response;
|
|
16304
|
+
try {
|
|
16305
|
+
response = await fetch(`http://127.0.0.1:${options.port}/api/v1/bootstrap`, {
|
|
16306
|
+
headers: { accept: "application/json" },
|
|
16307
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 1e3)
|
|
16308
|
+
});
|
|
16309
|
+
} catch {
|
|
16310
|
+
return unreachable;
|
|
16311
|
+
}
|
|
16312
|
+
if (!response.ok) {
|
|
16313
|
+
return unreachable;
|
|
16314
|
+
}
|
|
16315
|
+
const payload = await response.json().catch(() => null);
|
|
16316
|
+
if (!payload || payload.api_version !== 1) {
|
|
16317
|
+
return unreachable;
|
|
16318
|
+
}
|
|
16319
|
+
const linkId = typeof payload.link_id === "string" ? payload.link_id : null;
|
|
16320
|
+
return {
|
|
16321
|
+
reachable: true,
|
|
16322
|
+
reusable: options.linkId ? linkId === options.linkId : true,
|
|
16323
|
+
linkId,
|
|
16324
|
+
version: typeof payload.version === "string" ? payload.version : null
|
|
16325
|
+
};
|
|
16326
|
+
}
|
|
16327
|
+
async function stopDaemonProcess(paths = resolveRuntimePaths()) {
|
|
16328
|
+
const status = await getDaemonStatus(paths);
|
|
16329
|
+
if (!status.running || !status.pid) {
|
|
16330
|
+
return status;
|
|
16331
|
+
}
|
|
16332
|
+
try {
|
|
16333
|
+
process.kill(status.pid, "SIGTERM");
|
|
16334
|
+
} catch {
|
|
16335
|
+
await rm9(pidFilePath(paths), { force: true }).catch(() => void 0);
|
|
16336
|
+
return await getDaemonStatus(paths);
|
|
16337
|
+
}
|
|
16338
|
+
for (let index = 0; index < 20; index += 1) {
|
|
16339
|
+
await wait(250);
|
|
16340
|
+
if (!isProcessAlive3(status.pid)) {
|
|
16341
|
+
break;
|
|
16342
|
+
}
|
|
16343
|
+
}
|
|
16344
|
+
if (isProcessAlive3(status.pid)) {
|
|
16345
|
+
try {
|
|
16346
|
+
process.kill(status.pid, "SIGKILL");
|
|
16347
|
+
} catch {
|
|
16348
|
+
}
|
|
16349
|
+
for (let index = 0; index < 10; index += 1) {
|
|
16350
|
+
await wait(250);
|
|
16351
|
+
if (!isProcessAlive3(status.pid)) {
|
|
16352
|
+
break;
|
|
16353
|
+
}
|
|
16354
|
+
}
|
|
16355
|
+
}
|
|
16356
|
+
if (!isProcessAlive3(status.pid) || !await pidBackedServiceIsReachable(paths)) {
|
|
16357
|
+
await rm9(pidFilePath(paths), { force: true }).catch(() => void 0);
|
|
16358
|
+
}
|
|
16359
|
+
return await getDaemonStatus(paths);
|
|
16360
|
+
}
|
|
16361
|
+
async function getDaemonStatus(paths = resolveRuntimePaths()) {
|
|
16362
|
+
const pidFile = pidFilePath(paths);
|
|
16363
|
+
const pid = await readPid(pidFile);
|
|
16364
|
+
if (pid && !isProcessAlive3(pid)) {
|
|
16365
|
+
await rm9(pidFile, { force: true }).catch(() => void 0);
|
|
16366
|
+
return {
|
|
16367
|
+
running: false,
|
|
16368
|
+
pid: null,
|
|
16369
|
+
pidFile,
|
|
16370
|
+
logFile: daemonLogFile(paths)
|
|
16371
|
+
};
|
|
16372
|
+
}
|
|
16373
|
+
return {
|
|
16374
|
+
running: Boolean(pid),
|
|
16375
|
+
pid,
|
|
16376
|
+
pidFile,
|
|
16377
|
+
logFile: daemonLogFile(paths)
|
|
16378
|
+
};
|
|
16379
|
+
}
|
|
16380
|
+
function daemonLogFile(paths = resolveRuntimePaths()) {
|
|
16381
|
+
return getDaemonLogFile(paths);
|
|
16382
|
+
}
|
|
16383
|
+
function currentCliScriptPath() {
|
|
16384
|
+
return process.argv[1];
|
|
16385
|
+
}
|
|
16386
|
+
async function readPid(filePath) {
|
|
16387
|
+
const raw = await readFile15(filePath, "utf8").catch(() => null);
|
|
16388
|
+
if (!raw) {
|
|
16389
|
+
return null;
|
|
16390
|
+
}
|
|
16391
|
+
const pid = Number.parseInt(raw.trim(), 10);
|
|
16392
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
16393
|
+
}
|
|
16394
|
+
function isProcessAlive3(pid) {
|
|
16395
|
+
try {
|
|
16396
|
+
process.kill(pid, 0);
|
|
16397
|
+
return true;
|
|
16398
|
+
} catch {
|
|
16399
|
+
return false;
|
|
16400
|
+
}
|
|
16401
|
+
}
|
|
16402
|
+
async function pidBackedServiceIsReachable(paths) {
|
|
16403
|
+
const config = await loadConfig(paths).catch(() => null);
|
|
16404
|
+
if (!config) {
|
|
16405
|
+
return false;
|
|
16406
|
+
}
|
|
16407
|
+
return (await probeLocalLinkService({ port: config.port, timeoutMs: 500 })).reachable;
|
|
16408
|
+
}
|
|
16409
|
+
function wait(ms) {
|
|
16410
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16411
|
+
}
|
|
16412
|
+
|
|
16413
|
+
// src/link/updates.ts
|
|
15889
16414
|
var SERVER_LINK_CURRENT_RELEASE_PATH = "/api/v1/link/releases/current";
|
|
15890
16415
|
var LINK_NPM_PACKAGE = "@hermespilot/link";
|
|
15891
16416
|
var UPDATE_LOG_FILE2 = "link-update.log";
|
|
@@ -15893,6 +16418,7 @@ var UPDATE_LOG_MAX_FILES2 = 3;
|
|
|
15893
16418
|
var UPDATE_FETCH_TIMEOUT_MS = 5e3;
|
|
15894
16419
|
var MAX_UPDATE_LOG_LINES2 = 240;
|
|
15895
16420
|
var MAX_OUTPUT_LINE_LENGTH3 = 1200;
|
|
16421
|
+
var AUTO_RESTART_DELAY_MS = 1500;
|
|
15896
16422
|
var updateEvents2 = new EventEmitter4();
|
|
15897
16423
|
var runningUpdate2 = null;
|
|
15898
16424
|
async function readLinkUpdateCheck(options) {
|
|
@@ -15970,7 +16496,7 @@ async function startLinkUpdate(options) {
|
|
|
15970
16496
|
error: null,
|
|
15971
16497
|
manual_command: manualCommand
|
|
15972
16498
|
};
|
|
15973
|
-
await
|
|
16499
|
+
await mkdir16(options.paths.runDir, { recursive: true, mode: 448 });
|
|
15974
16500
|
await writer.write(
|
|
15975
16501
|
`
|
|
15976
16502
|
=== link update started ${startedAt} target=${targetVersion} ===
|
|
@@ -15979,7 +16505,7 @@ async function startLinkUpdate(options) {
|
|
|
15979
16505
|
await writer.write(`$ ${manualCommand}
|
|
15980
16506
|
`);
|
|
15981
16507
|
await writeUpdateState2(options.paths, started);
|
|
15982
|
-
const child =
|
|
16508
|
+
const child = spawn5(
|
|
15983
16509
|
resolveNpmBin(),
|
|
15984
16510
|
["install", "-g", `${LINK_NPM_PACKAGE}@${targetVersion}`],
|
|
15985
16511
|
{
|
|
@@ -16044,12 +16570,16 @@ async function startLinkUpdate(options) {
|
|
|
16044
16570
|
if (succeeded) {
|
|
16045
16571
|
await writer.write(
|
|
16046
16572
|
`
|
|
16047
|
-
[restart-
|
|
16573
|
+
[restart-scheduled] Hermes Link will restart automatically. If it does not reconnect, run \`${LINK_COMMAND} restart\` on this computer.
|
|
16048
16574
|
`
|
|
16049
16575
|
);
|
|
16050
16576
|
}
|
|
16051
16577
|
await writeUpdateState2(options.paths, state);
|
|
16052
16578
|
await emitUpdateStatus2(options.paths);
|
|
16579
|
+
if (succeeded) {
|
|
16580
|
+
await writer.flush();
|
|
16581
|
+
scheduleAutomaticRestart(options);
|
|
16582
|
+
}
|
|
16053
16583
|
void options.logger?.info(
|
|
16054
16584
|
succeeded ? "link_update_restart_required" : "link_update_failed",
|
|
16055
16585
|
{
|
|
@@ -16074,6 +16604,22 @@ async function startLinkUpdate(options) {
|
|
|
16074
16604
|
});
|
|
16075
16605
|
return readLinkUpdateStatus(options.paths);
|
|
16076
16606
|
}
|
|
16607
|
+
function scheduleAutomaticRestart(options) {
|
|
16608
|
+
const scriptPath = currentCliScriptPath();
|
|
16609
|
+
setTimeout(() => {
|
|
16610
|
+
const child = spawn5(process.execPath, [scriptPath, "restart"], {
|
|
16611
|
+
detached: true,
|
|
16612
|
+
stdio: "ignore",
|
|
16613
|
+
env: process.env,
|
|
16614
|
+
windowsHide: true
|
|
16615
|
+
});
|
|
16616
|
+
child.unref();
|
|
16617
|
+
void options.logger?.info("link_update_restart_scheduled", {
|
|
16618
|
+
delay_ms: AUTO_RESTART_DELAY_MS,
|
|
16619
|
+
command: `${LINK_COMMAND} restart`
|
|
16620
|
+
});
|
|
16621
|
+
}, AUTO_RESTART_DELAY_MS).unref();
|
|
16622
|
+
}
|
|
16077
16623
|
async function readLinkUpdateStatus(paths) {
|
|
16078
16624
|
let state = await readJsonFile(updateStatePath2(paths));
|
|
16079
16625
|
if (state?.state === "restart_required" && state.target_version) {
|
|
@@ -16086,7 +16632,7 @@ async function readLinkUpdateStatus(paths) {
|
|
|
16086
16632
|
await writeUpdateState2(paths, state);
|
|
16087
16633
|
}
|
|
16088
16634
|
}
|
|
16089
|
-
if (state?.state === "running" && !runningUpdate2 && !isRecentRunningState3(state) && !
|
|
16635
|
+
if (state?.state === "running" && !runningUpdate2 && !isRecentRunningState3(state) && !isProcessAlive4(state.pid)) {
|
|
16090
16636
|
state = {
|
|
16091
16637
|
...state,
|
|
16092
16638
|
state: "failed",
|
|
@@ -16239,7 +16785,7 @@ async function writeUpdateState2(paths, state) {
|
|
|
16239
16785
|
await writeJsonFile(updateStatePath2(paths), state);
|
|
16240
16786
|
}
|
|
16241
16787
|
async function readUpdateLogLines2(paths) {
|
|
16242
|
-
const raw = await
|
|
16788
|
+
const raw = await readFile16(updateLogPath2(paths), "utf8").catch(() => "");
|
|
16243
16789
|
if (!raw.trim()) {
|
|
16244
16790
|
return [];
|
|
16245
16791
|
}
|
|
@@ -16248,18 +16794,18 @@ async function readUpdateLogLines2(paths) {
|
|
|
16248
16794
|
);
|
|
16249
16795
|
}
|
|
16250
16796
|
function updateStatePath2(paths) {
|
|
16251
|
-
return
|
|
16797
|
+
return path21.join(paths.runDir, "link-update-state.json");
|
|
16252
16798
|
}
|
|
16253
16799
|
function updateLogPath2(paths) {
|
|
16254
|
-
return
|
|
16800
|
+
return path21.join(paths.logsDir, UPDATE_LOG_FILE2);
|
|
16255
16801
|
}
|
|
16256
16802
|
async function clearUpdateLogFiles2(paths) {
|
|
16257
16803
|
const primary = updateLogPath2(paths);
|
|
16258
16804
|
await Promise.all([
|
|
16259
|
-
|
|
16805
|
+
rm10(primary, { force: true }).catch(() => void 0),
|
|
16260
16806
|
...Array.from(
|
|
16261
16807
|
{ length: UPDATE_LOG_MAX_FILES2 },
|
|
16262
|
-
(_, index) =>
|
|
16808
|
+
(_, index) => rm10(`${primary}.${index + 1}`, { force: true }).catch(() => void 0)
|
|
16263
16809
|
)
|
|
16264
16810
|
]);
|
|
16265
16811
|
}
|
|
@@ -16292,7 +16838,7 @@ function isRecentRunningState3(state, now = Date.now()) {
|
|
|
16292
16838
|
const startedAt = state.started_at ? Date.parse(state.started_at) : Number.NaN;
|
|
16293
16839
|
return Number.isFinite(startedAt) && now - startedAt < 1e4;
|
|
16294
16840
|
}
|
|
16295
|
-
function
|
|
16841
|
+
function isProcessAlive4(pid) {
|
|
16296
16842
|
if (!pid || pid <= 0) {
|
|
16297
16843
|
return false;
|
|
16298
16844
|
}
|
|
@@ -16315,8 +16861,8 @@ function readString15(payload, key) {
|
|
|
16315
16861
|
}
|
|
16316
16862
|
|
|
16317
16863
|
// src/pairing/pairing.ts
|
|
16318
|
-
import
|
|
16319
|
-
import { rm as
|
|
16864
|
+
import path22 from "path";
|
|
16865
|
+
import { rm as rm11 } from "fs/promises";
|
|
16320
16866
|
|
|
16321
16867
|
// src/relay/bootstrap.ts
|
|
16322
16868
|
async function bootstrapRelayLink(options) {
|
|
@@ -16632,7 +17178,7 @@ async function readPairingClaim(sessionId, paths = resolveRuntimePaths()) {
|
|
|
16632
17178
|
};
|
|
16633
17179
|
}
|
|
16634
17180
|
async function clearPairingClaim(sessionId, paths = resolveRuntimePaths()) {
|
|
16635
|
-
await
|
|
17181
|
+
await rm11(pairingClaimPath(sessionId, paths), { force: true }).catch(() => void 0);
|
|
16636
17182
|
}
|
|
16637
17183
|
async function claimPairing(input) {
|
|
16638
17184
|
const paths = input.paths ?? resolveRuntimePaths();
|
|
@@ -16680,8 +17226,8 @@ async function loadRequiredIdentity2(paths) {
|
|
|
16680
17226
|
}
|
|
16681
17227
|
return identity;
|
|
16682
17228
|
}
|
|
16683
|
-
async function postServerJson(serverBaseUrl,
|
|
16684
|
-
const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
17229
|
+
async function postServerJson(serverBaseUrl, path23, body) {
|
|
17230
|
+
const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path23}`, {
|
|
16685
17231
|
method: "POST",
|
|
16686
17232
|
headers: {
|
|
16687
17233
|
accept: "application/json",
|
|
@@ -16691,8 +17237,8 @@ async function postServerJson(serverBaseUrl, path22, body) {
|
|
|
16691
17237
|
});
|
|
16692
17238
|
return readJsonResponse2(response);
|
|
16693
17239
|
}
|
|
16694
|
-
async function patchServerJson(serverBaseUrl,
|
|
16695
|
-
const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
17240
|
+
async function patchServerJson(serverBaseUrl, path23, token, body) {
|
|
17241
|
+
const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path23}`, {
|
|
16696
17242
|
method: "PATCH",
|
|
16697
17243
|
headers: {
|
|
16698
17244
|
accept: "application/json",
|
|
@@ -16726,7 +17272,7 @@ function defaultDisplayName() {
|
|
|
16726
17272
|
return `Hermes Link ${process.platform}`;
|
|
16727
17273
|
}
|
|
16728
17274
|
function pairingClaimPath(sessionId, paths) {
|
|
16729
|
-
return
|
|
17275
|
+
return path22.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
|
|
16730
17276
|
}
|
|
16731
17277
|
function qrPreferredUrls(routes) {
|
|
16732
17278
|
return routes.preferredUrls.filter((url) => !url.includes("/api/v1/relay/links/")).slice(0, 1);
|
|
@@ -17392,20 +17938,14 @@ async function createApp(options = {}) {
|
|
|
17392
17938
|
export {
|
|
17393
17939
|
LINK_VERSION,
|
|
17394
17940
|
LINK_COMMAND,
|
|
17395
|
-
migrateLinkDatabase,
|
|
17396
17941
|
resolveHermesProfileDir,
|
|
17397
17942
|
resolveHermesConfigPath,
|
|
17398
17943
|
readHermesApiServerConfig,
|
|
17399
17944
|
ensureHermesApiServerConfig,
|
|
17400
|
-
syncHermesLinkCronDeliveries,
|
|
17401
17945
|
LinkHttpError,
|
|
17402
17946
|
resolveRuntimePaths,
|
|
17403
|
-
createFileLogger,
|
|
17404
17947
|
getLinkLogFile,
|
|
17405
|
-
getDaemonLogFile,
|
|
17406
|
-
createRotatingTextLogWriter,
|
|
17407
17948
|
ensureHermesApiServerAvailable,
|
|
17408
|
-
ConversationService,
|
|
17409
17949
|
loadConfig,
|
|
17410
17950
|
loadIdentity,
|
|
17411
17951
|
ensureIdentity,
|
|
@@ -17414,6 +17954,14 @@ export {
|
|
|
17414
17954
|
preparePairing,
|
|
17415
17955
|
readPairingClaim,
|
|
17416
17956
|
clearPairingClaim,
|
|
17417
|
-
createApp
|
|
17957
|
+
createApp,
|
|
17958
|
+
startLinkService,
|
|
17959
|
+
startDaemonProcess,
|
|
17960
|
+
runDaemonSupervisor,
|
|
17961
|
+
probeLocalLinkService,
|
|
17962
|
+
stopDaemonProcess,
|
|
17963
|
+
getDaemonStatus,
|
|
17964
|
+
daemonLogFile,
|
|
17965
|
+
currentCliScriptPath
|
|
17418
17966
|
};
|
|
17419
|
-
//# sourceMappingURL=chunk-
|
|
17967
|
+
//# sourceMappingURL=chunk-4YF43CT4.js.map
|