tesseract-agent 0.11.1 → 0.11.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.
- package/dist-bundle/cli.js +790 -255
- package/dist-bundle/mesh-core/package.json +1 -1
- package/package.json +1 -1
package/dist-bundle/cli.js
CHANGED
|
@@ -79502,7 +79502,7 @@ function alphabet(letters) {
|
|
|
79502
79502
|
};
|
|
79503
79503
|
}
|
|
79504
79504
|
// @__NO_SIDE_EFFECTS__
|
|
79505
|
-
function
|
|
79505
|
+
function join67(separator = "") {
|
|
79506
79506
|
astr("join", separator);
|
|
79507
79507
|
return {
|
|
79508
79508
|
encode: (from) => {
|
|
@@ -79707,7 +79707,7 @@ var init_esm = __esm({
|
|
|
79707
79707
|
convertRadix2,
|
|
79708
79708
|
radix,
|
|
79709
79709
|
radix2,
|
|
79710
|
-
join:
|
|
79710
|
+
join: join67,
|
|
79711
79711
|
padding
|
|
79712
79712
|
};
|
|
79713
79713
|
}
|
|
@@ -81254,7 +81254,7 @@ var mesh_ca_exports = {};
|
|
|
81254
81254
|
__export(mesh_ca_exports, {
|
|
81255
81255
|
netCaCommand: () => netCaCommand
|
|
81256
81256
|
});
|
|
81257
|
-
import { chmodSync as chmodSync8, existsSync as
|
|
81257
|
+
import { chmodSync as chmodSync8, existsSync as existsSync49, mkdirSync as mkdirSync45, readFileSync as readFileSync54, writeFileSync as writeFileSync46 } from "node:fs";
|
|
81258
81258
|
import { join as join87, resolve as resolve13 } from "node:path";
|
|
81259
81259
|
import { createInterface as createInterface2 } from "node:readline";
|
|
81260
81260
|
function die(msg) {
|
|
@@ -81302,12 +81302,12 @@ function ensureDir(p) {
|
|
|
81302
81302
|
async function openCa(dir2) {
|
|
81303
81303
|
const gPath = join87(dir2, "genesis.bin");
|
|
81304
81304
|
const sPath = join87(dir2, "ca.sealed");
|
|
81305
|
-
if (!
|
|
81305
|
+
if (!existsSync49(gPath) || !existsSync49(sPath)) {
|
|
81306
81306
|
die(`No mesh CA in ${dir2}. Run: tesseract-agent net init --org NAME --ca-dir ${dir2}`);
|
|
81307
81307
|
}
|
|
81308
|
-
const genesisBytes = new Uint8Array(
|
|
81308
|
+
const genesisBytes = new Uint8Array(readFileSync54(gPath));
|
|
81309
81309
|
const genesis = decodeGenesis(genesisBytes);
|
|
81310
|
-
const sealed = decodeRecoveryBundle(new Uint8Array(
|
|
81310
|
+
const sealed = decodeRecoveryBundle(new Uint8Array(readFileSync54(sPath)));
|
|
81311
81311
|
const pass = await readPassphrase("CA passphrase: ");
|
|
81312
81312
|
let seed;
|
|
81313
81313
|
try {
|
|
@@ -81323,7 +81323,7 @@ async function netCaCommand(rest, flags) {
|
|
|
81323
81323
|
if (sub === "init") {
|
|
81324
81324
|
const org = typeof flags.org === "string" ? flags.org.trim() : "";
|
|
81325
81325
|
if (!org) die("Usage: tesseract-agent net init --org NAME [--ca-dir DIR]");
|
|
81326
|
-
if (
|
|
81326
|
+
if (existsSync49(join87(caDir, "ca.sealed"))) {
|
|
81327
81327
|
die(`A mesh CA already exists in ${caDir}. Refusing to overwrite it.`);
|
|
81328
81328
|
}
|
|
81329
81329
|
const pass = await readPassphrase("New CA passphrase: ");
|
|
@@ -81481,7 +81481,7 @@ var init_mesh_ca = __esm({
|
|
|
81481
81481
|
|
|
81482
81482
|
// src/cli.ts
|
|
81483
81483
|
init_base_paths();
|
|
81484
|
-
import { existsSync as
|
|
81484
|
+
import { existsSync as existsSync50, mkdtempSync as mkdtempSync4, readFileSync as readFileSync56, rmSync as rmSync13 } from "node:fs";
|
|
81485
81485
|
import { createHash as createHash9 } from "node:crypto";
|
|
81486
81486
|
import { execFileSync as execFileSync6, spawn as spawn14 } from "node:child_process";
|
|
81487
81487
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
@@ -109557,7 +109557,7 @@ async function startLocalServer(opts) {
|
|
|
109557
109557
|
|
|
109558
109558
|
// ../../packages/host-core/dist/daemon-runtime.js
|
|
109559
109559
|
init_base_paths();
|
|
109560
|
-
import { readFileSync as readFileSync49, writeFileSync as writeFileSync40, existsSync as
|
|
109560
|
+
import { readFileSync as readFileSync49, writeFileSync as writeFileSync40, existsSync as existsSync39, mkdirSync as mkdirSync41, unlinkSync as unlinkSync6, chmodSync as chmodSync7, statSync as statSync14 } from "node:fs";
|
|
109561
109561
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
109562
109562
|
import { join as join77 } from "node:path";
|
|
109563
109563
|
import { randomBytes as randomBytes10 } from "node:crypto";
|
|
@@ -109819,6 +109819,7 @@ async function getPeerIdentityPub(opts) {
|
|
|
109819
109819
|
// ../../packages/host-core/dist/mesh/node.js
|
|
109820
109820
|
import { createSocket as createSocket2 } from "node:dgram";
|
|
109821
109821
|
import { createRequire as createRequire4 } from "node:module";
|
|
109822
|
+
init_credentials();
|
|
109822
109823
|
|
|
109823
109824
|
// ../../packages/host-core/dist/mesh/bundle-gossip.js
|
|
109824
109825
|
var BundleOfferLedger = class {
|
|
@@ -109850,15 +109851,423 @@ var BundleOfferLedger = class {
|
|
|
109850
109851
|
}
|
|
109851
109852
|
};
|
|
109852
109853
|
|
|
109854
|
+
// ../../packages/host-core/dist/mesh/netd-engine.js
|
|
109855
|
+
init_dist6();
|
|
109856
|
+
|
|
109857
|
+
// ../../packages/host-core/dist/mesh/netd-client.js
|
|
109858
|
+
import { connect as connect2 } from "node:net";
|
|
109859
|
+
import { platform as platform3 } from "node:process";
|
|
109860
|
+
var NETD_WIRE_VERSION = 2;
|
|
109861
|
+
var MAX_LINE = 1024 * 1024;
|
|
109862
|
+
var TIMEOUT_MS3 = 15e3;
|
|
109863
|
+
function netdEndpoint() {
|
|
109864
|
+
if (platform3 === "win32")
|
|
109865
|
+
return "\\\\.\\pipe\\tesseract-netd";
|
|
109866
|
+
if (platform3 === "darwin")
|
|
109867
|
+
return "/var/run/tesseract-netd.sock";
|
|
109868
|
+
return "/run/tesseract-netd.sock";
|
|
109869
|
+
}
|
|
109870
|
+
function endpointOverride() {
|
|
109871
|
+
return process.env.CCB_NETD_SOCKET ?? null;
|
|
109872
|
+
}
|
|
109873
|
+
function fail2(code, detail) {
|
|
109874
|
+
return { ok: false, code, detail };
|
|
109875
|
+
}
|
|
109876
|
+
async function call(line) {
|
|
109877
|
+
const endpoint2 = endpointOverride() ?? netdEndpoint();
|
|
109878
|
+
return new Promise((resolve16) => {
|
|
109879
|
+
let settled = false;
|
|
109880
|
+
const done = (r) => {
|
|
109881
|
+
if (settled)
|
|
109882
|
+
return;
|
|
109883
|
+
settled = true;
|
|
109884
|
+
try {
|
|
109885
|
+
sock.destroy();
|
|
109886
|
+
} catch {
|
|
109887
|
+
}
|
|
109888
|
+
resolve16(r);
|
|
109889
|
+
};
|
|
109890
|
+
let sock;
|
|
109891
|
+
try {
|
|
109892
|
+
sock = connect2(endpoint2);
|
|
109893
|
+
} catch (e) {
|
|
109894
|
+
return resolve16(fail2("not-installed", e instanceof Error ? e.message : String(e)));
|
|
109895
|
+
}
|
|
109896
|
+
const timer2 = setTimeout(() => {
|
|
109897
|
+
done(fail2("timeout", `no answer from the network helper in ${TIMEOUT_MS3}ms`));
|
|
109898
|
+
}, TIMEOUT_MS3);
|
|
109899
|
+
timer2.unref?.();
|
|
109900
|
+
sock.setTimeout(TIMEOUT_MS3);
|
|
109901
|
+
sock.on("timeout", () => {
|
|
109902
|
+
clearTimeout(timer2);
|
|
109903
|
+
done(fail2("timeout", "socket idle"));
|
|
109904
|
+
});
|
|
109905
|
+
sock.on("error", (e) => {
|
|
109906
|
+
clearTimeout(timer2);
|
|
109907
|
+
const absent = e.code === "ENOENT" || e.code === "ECONNREFUSED";
|
|
109908
|
+
done(fail2(absent ? "not-installed" : "io", e.message));
|
|
109909
|
+
});
|
|
109910
|
+
let buf = "";
|
|
109911
|
+
sock.on("data", (chunk) => {
|
|
109912
|
+
buf += chunk.toString("utf8");
|
|
109913
|
+
if (buf.length > MAX_LINE) {
|
|
109914
|
+
clearTimeout(timer2);
|
|
109915
|
+
done(fail2("protocol", "the helper sent an oversized line"));
|
|
109916
|
+
return;
|
|
109917
|
+
}
|
|
109918
|
+
const nl = buf.indexOf("\n");
|
|
109919
|
+
if (nl === -1)
|
|
109920
|
+
return;
|
|
109921
|
+
clearTimeout(timer2);
|
|
109922
|
+
done({ ok: true, line: buf.slice(0, nl) });
|
|
109923
|
+
});
|
|
109924
|
+
sock.on("close", () => {
|
|
109925
|
+
clearTimeout(timer2);
|
|
109926
|
+
done(fail2("protocol", "the helper closed the connection without answering"));
|
|
109927
|
+
});
|
|
109928
|
+
sock.on("connect", () => {
|
|
109929
|
+
sock.write(`${line}
|
|
109930
|
+
`);
|
|
109931
|
+
});
|
|
109932
|
+
});
|
|
109933
|
+
}
|
|
109934
|
+
function parse3(line) {
|
|
109935
|
+
let body;
|
|
109936
|
+
try {
|
|
109937
|
+
body = JSON.parse(line);
|
|
109938
|
+
} catch {
|
|
109939
|
+
return fail2("protocol", "the helper sent something that is not JSON");
|
|
109940
|
+
}
|
|
109941
|
+
if (typeof body !== "object" || body === null) {
|
|
109942
|
+
return fail2("protocol", "the helper sent something that is not an object");
|
|
109943
|
+
}
|
|
109944
|
+
const o = body;
|
|
109945
|
+
if (o.ok === false) {
|
|
109946
|
+
const code = typeof o.code === "string" ? o.code : "refused";
|
|
109947
|
+
const detail = typeof o.detail === "string" ? o.detail : "the helper refused";
|
|
109948
|
+
return fail2(code, detail);
|
|
109949
|
+
}
|
|
109950
|
+
if (o.ok !== true)
|
|
109951
|
+
return fail2("protocol", "the helper did not say whether it succeeded");
|
|
109952
|
+
return { ok: true, body: o };
|
|
109953
|
+
}
|
|
109954
|
+
async function request(line) {
|
|
109955
|
+
const r = await call(line);
|
|
109956
|
+
return r.ok ? parse3(r.line) : r;
|
|
109957
|
+
}
|
|
109958
|
+
function hex4(b) {
|
|
109959
|
+
return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
109960
|
+
}
|
|
109961
|
+
async function netdHello() {
|
|
109962
|
+
const r = await request(JSON.stringify({ op: "hello", wireVersion: NETD_WIRE_VERSION }));
|
|
109963
|
+
if (!r.ok)
|
|
109964
|
+
return r;
|
|
109965
|
+
const v = r.body.wireVersion;
|
|
109966
|
+
if (typeof v !== "number")
|
|
109967
|
+
return fail2("protocol", "the helper did not report a wire version");
|
|
109968
|
+
if (v !== NETD_WIRE_VERSION) {
|
|
109969
|
+
return fail2("wire-version", `the helper speaks ${v}, this build speaks ${NETD_WIRE_VERSION}`);
|
|
109970
|
+
}
|
|
109971
|
+
return { ok: true, wireVersion: v };
|
|
109972
|
+
}
|
|
109973
|
+
async function netdStatus() {
|
|
109974
|
+
const r = await request(JSON.stringify({ op: "status" }));
|
|
109975
|
+
if (!r.ok)
|
|
109976
|
+
return r;
|
|
109977
|
+
const meshes = Array.isArray(r.body.meshes) ? r.body.meshes.filter((m) => typeof m === "string") : [];
|
|
109978
|
+
const iface = typeof r.body.interface === "string" ? r.body.interface : null;
|
|
109979
|
+
return { ok: true, meshes, interface: iface };
|
|
109980
|
+
}
|
|
109981
|
+
async function netdUp(args) {
|
|
109982
|
+
const r = await request(JSON.stringify({
|
|
109983
|
+
op: "up",
|
|
109984
|
+
meshId: args.meshId,
|
|
109985
|
+
genesis: hex4(args.genesis),
|
|
109986
|
+
cert: hex4(args.cert),
|
|
109987
|
+
fullTunnel: args.fullTunnel === true,
|
|
109988
|
+
...args.staticPrivate ? { staticPrivate: hex4(args.staticPrivate) } : {},
|
|
109989
|
+
...args.bundle ? { bundle: hex4(args.bundle) } : {}
|
|
109990
|
+
}));
|
|
109991
|
+
return r.ok ? { ok: true } : r;
|
|
109992
|
+
}
|
|
109993
|
+
async function netdHint(args) {
|
|
109994
|
+
const r = await request(JSON.stringify({
|
|
109995
|
+
op: "hint",
|
|
109996
|
+
meshId: args.meshId,
|
|
109997
|
+
staticPub: hex4(args.staticPub),
|
|
109998
|
+
endpoints: args.endpoints,
|
|
109999
|
+
relayed: args.relayed === true
|
|
110000
|
+
}));
|
|
110001
|
+
return r.ok ? { ok: true } : r;
|
|
110002
|
+
}
|
|
110003
|
+
async function netdBundle(meshId, bundle) {
|
|
110004
|
+
const r = await request(JSON.stringify({ op: "bundle", meshId, bundle: hex4(bundle) }));
|
|
110005
|
+
return r.ok ? { ok: true } : r;
|
|
110006
|
+
}
|
|
110007
|
+
async function netdSetExitNode(meshId, staticPub) {
|
|
110008
|
+
const r = await request(JSON.stringify({
|
|
110009
|
+
op: "setExitNode",
|
|
110010
|
+
meshId,
|
|
110011
|
+
staticPub: staticPub ? hex4(staticPub) : null
|
|
110012
|
+
}));
|
|
110013
|
+
return r.ok ? { ok: true } : r;
|
|
110014
|
+
}
|
|
110015
|
+
async function netdNodeStatus(meshId) {
|
|
110016
|
+
const r = await request(JSON.stringify({ op: "nodeStatus", meshId }));
|
|
110017
|
+
if (!r.ok)
|
|
110018
|
+
return r;
|
|
110019
|
+
const b = r.body;
|
|
110020
|
+
const num2 = (k) => typeof b[k] === "number" ? b[k] : 0;
|
|
110021
|
+
const strs = (k) => Array.isArray(b[k]) ? b[k].filter((x) => typeof x === "string") : [];
|
|
110022
|
+
if (b.node !== true)
|
|
110023
|
+
return fail2("protocol", "the helper did not answer with a node status");
|
|
110024
|
+
const pubHex = typeof b.localStaticPub === "string" ? b.localStaticPub : "";
|
|
110025
|
+
return {
|
|
110026
|
+
ok: true,
|
|
110027
|
+
node: {
|
|
110028
|
+
running: b.running === true,
|
|
110029
|
+
port: num2("port"),
|
|
110030
|
+
peers: num2("peers"),
|
|
110031
|
+
established: strs("established"),
|
|
110032
|
+
relayed: strs("relayed"),
|
|
110033
|
+
policyEpoch: num2("policyEpoch"),
|
|
110034
|
+
revoked: b.revoked === true,
|
|
110035
|
+
lastError: typeof b.lastError === "string" ? b.lastError : null,
|
|
110036
|
+
localStaticPub: Uint8Array.from(Buffer.from(pubHex, "hex")),
|
|
110037
|
+
meter: {
|
|
110038
|
+
txDirectBytes: num2("txDirectBytes"),
|
|
110039
|
+
txDirectPackets: num2("txDirectPackets"),
|
|
110040
|
+
txRelayedBytes: num2("txRelayedBytes"),
|
|
110041
|
+
txRelayedPackets: num2("txRelayedPackets"),
|
|
110042
|
+
rxDirectBytes: num2("rxDirectBytes"),
|
|
110043
|
+
rxDirectPackets: num2("rxDirectPackets"),
|
|
110044
|
+
rxRelayedBytes: num2("rxRelayedBytes"),
|
|
110045
|
+
rxRelayedPackets: num2("rxRelayedPackets"),
|
|
110046
|
+
forwardedBytes: num2("forwardedBytes"),
|
|
110047
|
+
forwardedPackets: num2("forwardedPackets")
|
|
110048
|
+
}
|
|
110049
|
+
}
|
|
110050
|
+
};
|
|
110051
|
+
}
|
|
110052
|
+
async function netdDown(meshId) {
|
|
110053
|
+
const r = await request(JSON.stringify({ op: "down", meshId }));
|
|
110054
|
+
return r.ok ? { ok: true } : r;
|
|
110055
|
+
}
|
|
110056
|
+
async function netdAvailable() {
|
|
110057
|
+
return (await netdHello()).ok;
|
|
110058
|
+
}
|
|
110059
|
+
|
|
110060
|
+
// ../../packages/host-core/dist/mesh/netd-engine.js
|
|
110061
|
+
var NETD_POLL_MS = 1e3;
|
|
110062
|
+
var NetdEngine = class {
|
|
110063
|
+
#meshDir;
|
|
110064
|
+
#meshId;
|
|
110065
|
+
#localStaticPub;
|
|
110066
|
+
#hooks;
|
|
110067
|
+
#snapshot = null;
|
|
110068
|
+
#pendingEndpoints = /* @__PURE__ */ new Map();
|
|
110069
|
+
#events = [];
|
|
110070
|
+
#seenEstablished = /* @__PURE__ */ new Set();
|
|
110071
|
+
#seenRelayed = /* @__PURE__ */ new Set();
|
|
110072
|
+
#timer = null;
|
|
110073
|
+
#announced = false;
|
|
110074
|
+
#lastError = null;
|
|
110075
|
+
#stopped = false;
|
|
110076
|
+
constructor(meshDir2, cert, hooks2) {
|
|
110077
|
+
this.#meshDir = meshDir2;
|
|
110078
|
+
this.#hooks = hooks2;
|
|
110079
|
+
const d = decodeCert(cert).details;
|
|
110080
|
+
this.#meshId = hex3(d.genesisFp);
|
|
110081
|
+
this.#localStaticPub = Buffer.from(d.staticPub);
|
|
110082
|
+
this.#timer = setInterval(() => void this.#poll(), NETD_POLL_MS);
|
|
110083
|
+
this.#timer.unref?.();
|
|
110084
|
+
void this.#poll();
|
|
110085
|
+
}
|
|
110086
|
+
/** Read netd's view now rather than waiting for the timer. Exposed for tests and for
|
|
110087
|
+
* the moment right after `up` so status does not lag a full interval. */
|
|
110088
|
+
async refresh() {
|
|
110089
|
+
await this.#poll();
|
|
110090
|
+
}
|
|
110091
|
+
async #poll() {
|
|
110092
|
+
if (this.#stopped)
|
|
110093
|
+
return;
|
|
110094
|
+
const r = await netdNodeStatus(this.#meshDir);
|
|
110095
|
+
if (!r.ok) {
|
|
110096
|
+
if (r.code !== "not-running" && r.code !== "not-installed") {
|
|
110097
|
+
this.#lastError = `netd: ${r.detail}`;
|
|
110098
|
+
}
|
|
110099
|
+
return;
|
|
110100
|
+
}
|
|
110101
|
+
const s = r.node;
|
|
110102
|
+
const prev = this.#snapshot;
|
|
110103
|
+
this.#snapshot = s;
|
|
110104
|
+
if (s.lastError)
|
|
110105
|
+
this.#lastError = s.lastError;
|
|
110106
|
+
for (const k of s.established) {
|
|
110107
|
+
if (!this.#seenEstablished.has(k)) {
|
|
110108
|
+
this.#seenEstablished.add(k);
|
|
110109
|
+
this.#events.push({ kind: "peerEstablished", staticPub: Buffer.from(k, "hex") });
|
|
110110
|
+
}
|
|
110111
|
+
}
|
|
110112
|
+
const relayedNow = new Set(s.relayed);
|
|
110113
|
+
for (const k of relayedNow) {
|
|
110114
|
+
if (!this.#seenRelayed.has(k)) {
|
|
110115
|
+
this.#seenRelayed.add(k);
|
|
110116
|
+
this.#events.push({ kind: "pathChanged", staticPub: Buffer.from(k, "hex"), detail: "relay" });
|
|
110117
|
+
}
|
|
110118
|
+
}
|
|
110119
|
+
for (const k of [...this.#seenRelayed]) {
|
|
110120
|
+
if (!relayedNow.has(k)) {
|
|
110121
|
+
this.#seenRelayed.delete(k);
|
|
110122
|
+
this.#events.push({ kind: "pathChanged", staticPub: Buffer.from(k, "hex"), detail: "direct" });
|
|
110123
|
+
}
|
|
110124
|
+
}
|
|
110125
|
+
if (s.running && s.port > 0 && !this.#announced) {
|
|
110126
|
+
this.#announced = true;
|
|
110127
|
+
this.#hooks.log?.(`mesh: node running in the network helper on UDP port ${s.port}`);
|
|
110128
|
+
this.#hooks.onUp(s.port);
|
|
110129
|
+
}
|
|
110130
|
+
void prev;
|
|
110131
|
+
}
|
|
110132
|
+
// ── MeshEngineNative ────────────────────────────────────────────────────────────
|
|
110133
|
+
setBundle(b, _nowMs) {
|
|
110134
|
+
void netdBundle(this.#meshDir, b).then((r) => {
|
|
110135
|
+
if (!r.ok)
|
|
110136
|
+
this.#lastError = `bundle: ${r.detail}`;
|
|
110137
|
+
});
|
|
110138
|
+
}
|
|
110139
|
+
addPeer(staticPub, _overlayV4, _overlayV6) {
|
|
110140
|
+
const k = staticPub.toString("hex");
|
|
110141
|
+
if (!this.#pendingEndpoints.has(k))
|
|
110142
|
+
this.#pendingEndpoints.set(k, { endpoints: [], relayed: false });
|
|
110143
|
+
}
|
|
110144
|
+
addPath(staticPub, endpoint2, relayed) {
|
|
110145
|
+
const k = staticPub.toString("hex");
|
|
110146
|
+
const p = this.#pendingEndpoints.get(k) ?? { endpoints: [], relayed: false };
|
|
110147
|
+
if (!p.endpoints.includes(endpoint2))
|
|
110148
|
+
p.endpoints.push(endpoint2);
|
|
110149
|
+
p.relayed = p.relayed || relayed;
|
|
110150
|
+
this.#pendingEndpoints.set(k, p);
|
|
110151
|
+
}
|
|
110152
|
+
startHandshake(staticPub, _nowMs) {
|
|
110153
|
+
const k = staticPub.toString("hex");
|
|
110154
|
+
const p = this.#pendingEndpoints.get(k) ?? { endpoints: [], relayed: false };
|
|
110155
|
+
this.#pendingEndpoints.delete(k);
|
|
110156
|
+
void netdHint({ meshId: this.#meshDir, staticPub, endpoints: p.endpoints, relayed: p.relayed }).then((r) => {
|
|
110157
|
+
if (!r.ok)
|
|
110158
|
+
this.#lastError = `hint: ${r.detail}`;
|
|
110159
|
+
});
|
|
110160
|
+
}
|
|
110161
|
+
/** No UDP here — netd owns the socket. Never called in practice; kept for the interface. */
|
|
110162
|
+
injectUdp(_pkt, _from, _nowMs) {
|
|
110163
|
+
}
|
|
110164
|
+
tick(_nowMs) {
|
|
110165
|
+
}
|
|
110166
|
+
pollSend() {
|
|
110167
|
+
return null;
|
|
110168
|
+
}
|
|
110169
|
+
pollEvent() {
|
|
110170
|
+
return this.#events.shift() ?? null;
|
|
110171
|
+
}
|
|
110172
|
+
meter() {
|
|
110173
|
+
const m = this.#snapshot?.meter;
|
|
110174
|
+
const tx = (m?.txDirectBytes ?? 0) + (m?.txRelayedBytes ?? 0);
|
|
110175
|
+
return {
|
|
110176
|
+
txDirectBytes: m?.txDirectBytes ?? 0,
|
|
110177
|
+
txRelayedBytes: m?.txRelayedBytes ?? 0,
|
|
110178
|
+
rxDirectBytes: m?.rxDirectBytes ?? 0,
|
|
110179
|
+
rxRelayedBytes: m?.rxRelayedBytes ?? 0,
|
|
110180
|
+
forwardedBytes: m?.forwardedBytes ?? 0,
|
|
110181
|
+
forwardedPackets: m?.forwardedPackets ?? 0,
|
|
110182
|
+
relayedTxFraction: tx === 0 ? 0 : (m?.txRelayedBytes ?? 0) / tx
|
|
110183
|
+
};
|
|
110184
|
+
}
|
|
110185
|
+
localStaticPub() {
|
|
110186
|
+
return this.#localStaticPub;
|
|
110187
|
+
}
|
|
110188
|
+
meshId() {
|
|
110189
|
+
return this.#meshId;
|
|
110190
|
+
}
|
|
110191
|
+
policyEpoch() {
|
|
110192
|
+
return this.#snapshot?.policyEpoch ?? 0;
|
|
110193
|
+
}
|
|
110194
|
+
selfRevoked() {
|
|
110195
|
+
return this.#snapshot?.revoked === true;
|
|
110196
|
+
}
|
|
110197
|
+
peerCount() {
|
|
110198
|
+
return this.#snapshot?.peers ?? 0;
|
|
110199
|
+
}
|
|
110200
|
+
setExitNode(staticPub) {
|
|
110201
|
+
void netdSetExitNode(this.#meshDir, staticPub).then((r) => {
|
|
110202
|
+
if (!r.ok)
|
|
110203
|
+
this.#lastError = `exit node: ${r.detail}`;
|
|
110204
|
+
});
|
|
110205
|
+
}
|
|
110206
|
+
/** Is netd running the node right now, and on which port? */
|
|
110207
|
+
get running() {
|
|
110208
|
+
return this.#snapshot?.running === true;
|
|
110209
|
+
}
|
|
110210
|
+
get port() {
|
|
110211
|
+
return this.#snapshot && this.#snapshot.port > 0 ? this.#snapshot.port : null;
|
|
110212
|
+
}
|
|
110213
|
+
get lastError() {
|
|
110214
|
+
return this.#lastError;
|
|
110215
|
+
}
|
|
110216
|
+
stop() {
|
|
110217
|
+
this.#stopped = true;
|
|
110218
|
+
if (this.#timer) {
|
|
110219
|
+
clearInterval(this.#timer);
|
|
110220
|
+
this.#timer = null;
|
|
110221
|
+
}
|
|
110222
|
+
}
|
|
110223
|
+
};
|
|
110224
|
+
|
|
110225
|
+
// ../../packages/host-core/dist/mesh/node.js
|
|
110226
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
110227
|
+
|
|
110228
|
+
// ../../packages/host-core/dist/mesh/bundle-refresh.js
|
|
110229
|
+
init_dist6();
|
|
110230
|
+
var CONTEXT = "tsr-bundle-fetch-v1";
|
|
110231
|
+
var REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
110232
|
+
async function fetchBundle(args) {
|
|
110233
|
+
const none = { bundle: null, epoch: null };
|
|
110234
|
+
try {
|
|
110235
|
+
const ts = Date.now();
|
|
110236
|
+
const { privateKey } = await signingKeyFromSeed(args.sigPrivate);
|
|
110237
|
+
const message = new TextEncoder().encode(`${CONTEXT}
|
|
110238
|
+
${args.genesisFp.toLowerCase()}
|
|
110239
|
+
${args.staticPub.toLowerCase()}
|
|
110240
|
+
${ts}`);
|
|
110241
|
+
const sig = await sign2(privateKey, message);
|
|
110242
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
110243
|
+
const res = await doFetch(`${args.origin.replace(/\/$/, "")}/api/core/tesseract/mesh/meshes/by-genesis/${encodeURIComponent(args.genesisFp.toLowerCase())}/bundle`, {
|
|
110244
|
+
method: "GET",
|
|
110245
|
+
headers: {
|
|
110246
|
+
"x-tsr-node": args.staticPub.toLowerCase(),
|
|
110247
|
+
"x-tsr-ts": String(ts),
|
|
110248
|
+
"x-tsr-sig": Buffer.from(sig).toString("base64")
|
|
110249
|
+
}
|
|
110250
|
+
});
|
|
110251
|
+
if (!res.ok)
|
|
110252
|
+
return none;
|
|
110253
|
+
const body = await res.json();
|
|
110254
|
+
if (!body.bundle)
|
|
110255
|
+
return none;
|
|
110256
|
+
return { bundle: Uint8Array.from(Buffer.from(body.bundle, "hex")), epoch: body.epoch ?? null };
|
|
110257
|
+
} catch {
|
|
110258
|
+
return none;
|
|
110259
|
+
}
|
|
110260
|
+
}
|
|
110261
|
+
|
|
109853
110262
|
// ../../packages/host-core/dist/mesh/config.js
|
|
109854
110263
|
init_credentials();
|
|
109855
110264
|
import { chmodSync as chmodSync5, existsSync as existsSync33, mkdirSync as mkdirSync36, readdirSync as readdirSync12, readFileSync as readFileSync47, renameSync as renameSync11, rmSync as rmSync7, writeFileSync as writeFileSync35 } from "node:fs";
|
|
109856
|
-
import { dirname as dirname31, join as
|
|
110265
|
+
import { dirname as dirname31, join as join68 } from "node:path";
|
|
109857
110266
|
function meshDir() {
|
|
109858
|
-
return
|
|
110267
|
+
return join68(daemonDir2(), "mesh");
|
|
109859
110268
|
}
|
|
109860
110269
|
function meshesDir() {
|
|
109861
|
-
return
|
|
110270
|
+
return join68(meshDir(), "meshes");
|
|
109862
110271
|
}
|
|
109863
110272
|
var MESH_DIR_NAME_BYTES = 8;
|
|
109864
110273
|
function meshDirName(genesisFp) {
|
|
@@ -109876,7 +110285,7 @@ function oneMeshDir(meshId) {
|
|
|
109876
110285
|
if (!isMeshId(meshId)) {
|
|
109877
110286
|
throw new Error(`not a mesh id: ${JSON.stringify(meshId.slice(0, 64))}`);
|
|
109878
110287
|
}
|
|
109879
|
-
return
|
|
110288
|
+
return join68(meshesDir(), meshId);
|
|
109880
110289
|
}
|
|
109881
110290
|
var LEGACY_MESH_ID = "legacy";
|
|
109882
110291
|
var CERT_GENESIS_FP_OFFSET = 19;
|
|
@@ -109894,7 +110303,7 @@ var FILES = {
|
|
|
109894
110303
|
local: "local.json"
|
|
109895
110304
|
};
|
|
109896
110305
|
function readIfPresent(name, dir2 = meshDir()) {
|
|
109897
|
-
const p =
|
|
110306
|
+
const p = join68(dir2, name);
|
|
109898
110307
|
try {
|
|
109899
110308
|
return existsSync33(p) ? new Uint8Array(readFileSync47(p)) : void 0;
|
|
109900
110309
|
} catch {
|
|
@@ -109902,7 +110311,7 @@ function readIfPresent(name, dir2 = meshDir()) {
|
|
|
109902
110311
|
}
|
|
109903
110312
|
}
|
|
109904
110313
|
function migrateSingleMesh() {
|
|
109905
|
-
const legacyGenesis =
|
|
110314
|
+
const legacyGenesis = join68(meshDir(), FILES.genesis);
|
|
109906
110315
|
if (!existsSync33(legacyGenesis))
|
|
109907
110316
|
return null;
|
|
109908
110317
|
const id = meshIdFromCert(readIfPresent(FILES.cert)) ?? LEGACY_MESH_ID;
|
|
@@ -109911,11 +110320,11 @@ function migrateSingleMesh() {
|
|
|
109911
110320
|
mkdirSync36(dest, { recursive: true, mode: 448 });
|
|
109912
110321
|
chmodSync5(dest, 448);
|
|
109913
110322
|
for (const f of Object.values(FILES)) {
|
|
109914
|
-
const from =
|
|
110323
|
+
const from = join68(meshDir(), f);
|
|
109915
110324
|
if (existsSync33(from))
|
|
109916
|
-
renameSync11(from,
|
|
110325
|
+
renameSync11(from, join68(dest, f));
|
|
109917
110326
|
}
|
|
109918
|
-
const key2 =
|
|
110327
|
+
const key2 = join68(dest, FILES.key);
|
|
109919
110328
|
if (existsSync33(key2))
|
|
109920
110329
|
chmodSync5(key2, 384);
|
|
109921
110330
|
} catch {
|
|
@@ -109939,7 +110348,7 @@ function listMeshIds() {
|
|
|
109939
110348
|
}
|
|
109940
110349
|
function readLocal(meshId) {
|
|
109941
110350
|
try {
|
|
109942
|
-
return JSON.parse(readFileSync47(
|
|
110351
|
+
return JSON.parse(readFileSync47(join68(oneMeshDir(meshId), FILES.local), "utf8"));
|
|
109943
110352
|
} catch {
|
|
109944
110353
|
return null;
|
|
109945
110354
|
}
|
|
@@ -109947,7 +110356,7 @@ function readLocal(meshId) {
|
|
|
109947
110356
|
function writeLocal(meshId, state3) {
|
|
109948
110357
|
try {
|
|
109949
110358
|
mkdirSync36(oneMeshDir(meshId), { recursive: true, mode: 448 });
|
|
109950
|
-
writeFileSync35(
|
|
110359
|
+
writeFileSync35(join68(oneMeshDir(meshId), FILES.local), JSON.stringify(state3, null, 2), { mode: 384 });
|
|
109951
110360
|
} catch {
|
|
109952
110361
|
}
|
|
109953
110362
|
}
|
|
@@ -109980,7 +110389,7 @@ function loadMeshIdentity() {
|
|
|
109980
110389
|
return first === void 0 ? null : loadMesh(first);
|
|
109981
110390
|
}
|
|
109982
110391
|
function writeSecret(name, bytes2, dir2 = meshDir()) {
|
|
109983
|
-
const p =
|
|
110392
|
+
const p = join68(dir2, name);
|
|
109984
110393
|
writeFileSync35(p, bytes2, { mode: 384 });
|
|
109985
110394
|
try {
|
|
109986
110395
|
chmodSync5(p, 384);
|
|
@@ -109998,11 +110407,11 @@ function saveMeshIdentity(id) {
|
|
|
109998
110407
|
chmodSync5(meshDir(), 448);
|
|
109999
110408
|
} catch {
|
|
110000
110409
|
}
|
|
110001
|
-
writeFileSync35(
|
|
110002
|
-
writeFileSync35(
|
|
110410
|
+
writeFileSync35(join68(meshDir(), FILES.genesis), id.genesis);
|
|
110411
|
+
writeFileSync35(join68(meshDir(), FILES.cert), id.cert);
|
|
110003
110412
|
writeSecret(FILES.key, id.staticPrivate);
|
|
110004
110413
|
if (id.bundle)
|
|
110005
|
-
writeFileSync35(
|
|
110414
|
+
writeFileSync35(join68(meshDir(), FILES.bundle), id.bundle);
|
|
110006
110415
|
}
|
|
110007
110416
|
function saveMesh(meshId, id) {
|
|
110008
110417
|
const dir2 = oneMeshDir(meshId);
|
|
@@ -110019,13 +110428,13 @@ function saveMesh(meshId, id) {
|
|
|
110019
110428
|
chmodSync5(dir2, 448);
|
|
110020
110429
|
} catch {
|
|
110021
110430
|
}
|
|
110022
|
-
writeFileSync35(
|
|
110023
|
-
writeFileSync35(
|
|
110431
|
+
writeFileSync35(join68(dir2, FILES.genesis), id.genesis);
|
|
110432
|
+
writeFileSync35(join68(dir2, FILES.cert), id.cert);
|
|
110024
110433
|
writeSecret(FILES.key, id.staticPrivate, dir2);
|
|
110025
110434
|
if (id.sigPrivate)
|
|
110026
110435
|
writeSecret(FILES.sigKey, id.sigPrivate, dir2);
|
|
110027
110436
|
if (id.bundle)
|
|
110028
|
-
writeFileSync35(
|
|
110437
|
+
writeFileSync35(join68(dir2, FILES.bundle), id.bundle);
|
|
110029
110438
|
if (readLocal(meshId) === null)
|
|
110030
110439
|
writeLocal(meshId, { joinedAt: Date.now() });
|
|
110031
110440
|
}
|
|
@@ -110035,7 +110444,7 @@ function removeMesh(meshId) {
|
|
|
110035
110444
|
var STATUS_REFRESH_MS = 5e3;
|
|
110036
110445
|
var STATUS_STALE_MS = 2e4;
|
|
110037
110446
|
function statusPath(meshId) {
|
|
110038
|
-
return meshId === void 0 ?
|
|
110447
|
+
return meshId === void 0 ? join68(meshDir(), "status.json") : join68(oneMeshDir(meshId), "status.json");
|
|
110039
110448
|
}
|
|
110040
110449
|
function writeStatus(status2, meshId) {
|
|
110041
110450
|
try {
|
|
@@ -110066,7 +110475,7 @@ function cacheBundle(bundle, meshId) {
|
|
|
110066
110475
|
const id = meshId ?? listMeshIds()[0];
|
|
110067
110476
|
const dir2 = id === void 0 ? meshDir() : oneMeshDir(id);
|
|
110068
110477
|
mkdirSync36(dir2, { recursive: true, mode: 448 });
|
|
110069
|
-
writeFileSync35(
|
|
110478
|
+
writeFileSync35(join68(dir2, FILES.bundle), bundle);
|
|
110070
110479
|
} catch {
|
|
110071
110480
|
}
|
|
110072
110481
|
}
|
|
@@ -110222,6 +110631,9 @@ function loadMeshCore() {
|
|
|
110222
110631
|
}
|
|
110223
110632
|
var meshCore = loadMeshCore();
|
|
110224
110633
|
function meshEngineStatus() {
|
|
110634
|
+
if (process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint())) {
|
|
110635
|
+
return { available: true, reason: null };
|
|
110636
|
+
}
|
|
110225
110637
|
return { available: meshCore.available === true, reason: meshCore.loadError ?? null };
|
|
110226
110638
|
}
|
|
110227
110639
|
var TICK_MS2 = 1e3;
|
|
@@ -110317,6 +110729,8 @@ var MeshNode = class {
|
|
|
110317
110729
|
#engine = null;
|
|
110318
110730
|
#sock = null;
|
|
110319
110731
|
#timer = null;
|
|
110732
|
+
/** The policy refresh poll. See `bundle-refresh.ts` — this is what makes eviction real. */
|
|
110733
|
+
#refreshTimer = null;
|
|
110320
110734
|
#unsubscribe = null;
|
|
110321
110735
|
#identity = null;
|
|
110322
110736
|
/** The policy bundle we hold, as bytes, so we can OFFER it to a peer that is behind.
|
|
@@ -110389,8 +110803,11 @@ var MeshNode = class {
|
|
|
110389
110803
|
}
|
|
110390
110804
|
status() {
|
|
110391
110805
|
return {
|
|
110392
|
-
|
|
110393
|
-
|
|
110806
|
+
// In netd mode the engine is the helper's, and whether THIS process could load a
|
|
110807
|
+
// prebuilt is beside the point — a CLI install whose native fetch failed still has a
|
|
110808
|
+
// working network when the helper runs it, and must not say "engine unavailable".
|
|
110809
|
+
available: this.#engine instanceof NetdEngine ? true : meshCore.available,
|
|
110810
|
+
loadError: this.#engine instanceof NetdEngine ? null : meshCore.loadError,
|
|
110394
110811
|
enrolled: this.#identity !== null || this.#loadIdentity() !== null,
|
|
110395
110812
|
running: this.#engine !== null,
|
|
110396
110813
|
port: this.#port,
|
|
@@ -110407,7 +110824,22 @@ var MeshNode = class {
|
|
|
110407
110824
|
this.#established.has(hex6) ? this.#relayed.has(hex6) ? "relay" : "direct" : "none"
|
|
110408
110825
|
])),
|
|
110409
110826
|
meter: this.#engine?.meter() ?? null,
|
|
110410
|
-
|
|
110827
|
+
// THE POLICY EPOCH this node is actually running on.
|
|
110828
|
+
//
|
|
110829
|
+
// Read from the ENGINE, never from `bundle.bin`: the engine installs a bundle the
|
|
110830
|
+
// moment it verifies one, and a bundle pulled from a peer over the Noise session
|
|
110831
|
+
// never touches that file. Judging freshness by the file — which is what there was
|
|
110832
|
+
// to judge by — therefore reports a node as stale when it is current, and is how a
|
|
110833
|
+
// machine came to look a dozen epochs behind while carrying the right policy.
|
|
110834
|
+
//
|
|
110835
|
+
// It is the one number that answers "why is nothing passing": a node whose policy
|
|
110836
|
+
// predates a peer has no roster entry for it and drops every packet, correctly, with
|
|
110837
|
+
// nothing anywhere saying so.
|
|
110838
|
+
policyEpoch: this.#engine?.policyEpoch() ?? null,
|
|
110839
|
+
lastError: this.#lastError ?? (this.#engine instanceof NetdEngine ? this.#engine.lastError : null),
|
|
110840
|
+
// In netd mode "running" means netd runs it: an adapter with no node behind it yet
|
|
110841
|
+
// (routes not synced, helper just installed) is not a running node.
|
|
110842
|
+
...this.#engine instanceof NetdEngine && !this.#engine.running ? { running: false } : {},
|
|
110411
110843
|
// Surfaced so `net status` can say "removed" rather than "not running". Those look
|
|
110412
110844
|
// identical from outside and have completely different remedies.
|
|
110413
110845
|
removed: this.#revoked
|
|
@@ -110429,7 +110861,8 @@ var MeshNode = class {
|
|
|
110429
110861
|
reason: "this machine was removed from the network \u2014 ask an admin for a new invitation"
|
|
110430
110862
|
};
|
|
110431
110863
|
}
|
|
110432
|
-
|
|
110864
|
+
const inNetd = process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint());
|
|
110865
|
+
if (!inNetd && !meshCore.available) {
|
|
110433
110866
|
return { ok: false, reason: `mesh engine unavailable: ${meshCore.loadError ?? "no prebuilt"}` };
|
|
110434
110867
|
}
|
|
110435
110868
|
const id = this.#loadIdentity();
|
|
@@ -110439,20 +110872,46 @@ var MeshNode = class {
|
|
|
110439
110872
|
reason: this.#wantMeshId === null ? "this machine is not enrolled in a mesh" : `this machine is not enrolled in mesh ${this.#wantMeshId}`
|
|
110440
110873
|
};
|
|
110441
110874
|
}
|
|
110442
|
-
|
|
110443
|
-
|
|
110444
|
-
if (
|
|
110445
|
-
|
|
110446
|
-
|
|
110875
|
+
if (inNetd) {
|
|
110876
|
+
const meshDir2 = this.#wantMeshId ?? listMeshIds()[0] ?? null;
|
|
110877
|
+
if (!meshDir2)
|
|
110878
|
+
return { ok: false, reason: "this machine is not enrolled in a mesh" };
|
|
110879
|
+
try {
|
|
110880
|
+
this.#engine = new NetdEngine(meshDir2, id.cert, {
|
|
110881
|
+
// netd reports the node up: now this side has a port to advertise, and can
|
|
110882
|
+
// publish itself to the relay and the LAN. Before that there is nothing to say.
|
|
110883
|
+
onUp: (port) => {
|
|
110884
|
+
this.#port = port;
|
|
110885
|
+
this.#join();
|
|
110886
|
+
this.#startLan();
|
|
110887
|
+
this.#publishStatus();
|
|
110888
|
+
}
|
|
110889
|
+
});
|
|
110890
|
+
if (id.bundle)
|
|
110891
|
+
this.#bundle = id.bundle;
|
|
110892
|
+
} catch (e) {
|
|
110893
|
+
this.#engine = null;
|
|
110894
|
+
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110895
|
+
return { ok: false, reason: this.#lastError };
|
|
110896
|
+
}
|
|
110897
|
+
} else {
|
|
110898
|
+
try {
|
|
110899
|
+
this.#engine = new meshCore.MeshEngine(Buffer.from(id.genesis), Buffer.from(id.staticPrivate), Buffer.from(id.cert), 0, Buffer.alloc(16));
|
|
110900
|
+
if (id.bundle) {
|
|
110901
|
+
this.#engine.setBundle(Buffer.from(id.bundle), Date.now());
|
|
110902
|
+
this.#bundle = id.bundle;
|
|
110903
|
+
}
|
|
110904
|
+
} catch (e) {
|
|
110905
|
+
this.#engine = null;
|
|
110906
|
+
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110907
|
+
return { ok: false, reason: this.#lastError };
|
|
110447
110908
|
}
|
|
110448
|
-
} catch (e) {
|
|
110449
|
-
this.#engine = null;
|
|
110450
|
-
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110451
|
-
return { ok: false, reason: this.#lastError };
|
|
110452
110909
|
}
|
|
110453
110910
|
this.#identity = id;
|
|
110454
|
-
|
|
110455
|
-
|
|
110911
|
+
if (!inNetd) {
|
|
110912
|
+
this.#openSocket();
|
|
110913
|
+
this.#startLan();
|
|
110914
|
+
}
|
|
110456
110915
|
this.#offRejoin = onMeshRejoin(() => this.#join());
|
|
110457
110916
|
this.#publishStatus();
|
|
110458
110917
|
this.#statusTimer = setInterval(() => this.#publishStatus(), STATUS_REFRESH_MS);
|
|
@@ -110460,6 +110919,9 @@ var MeshNode = class {
|
|
|
110460
110919
|
this.#subscribe();
|
|
110461
110920
|
this.#timer = setInterval(() => this.#tick(), TICK_MS2);
|
|
110462
110921
|
this.#timer.unref?.();
|
|
110922
|
+
void this.#refreshBundle();
|
|
110923
|
+
this.#refreshTimer = setInterval(() => void this.#refreshBundle(), REFRESH_INTERVAL_MS);
|
|
110924
|
+
this.#refreshTimer.unref?.();
|
|
110463
110925
|
return { ok: true };
|
|
110464
110926
|
}
|
|
110465
110927
|
/** Tear down. Idempotent, and safe to call from a signal handler. */
|
|
@@ -110468,6 +110930,16 @@ var MeshNode = class {
|
|
|
110468
110930
|
clearInterval(this.#timer);
|
|
110469
110931
|
this.#timer = null;
|
|
110470
110932
|
}
|
|
110933
|
+
if (this.#refreshTimer) {
|
|
110934
|
+
clearInterval(this.#refreshTimer);
|
|
110935
|
+
this.#refreshTimer = null;
|
|
110936
|
+
}
|
|
110937
|
+
if (this.#engine instanceof NetdEngine) {
|
|
110938
|
+
try {
|
|
110939
|
+
this.#engine.stop();
|
|
110940
|
+
} catch {
|
|
110941
|
+
}
|
|
110942
|
+
}
|
|
110471
110943
|
this.#unsubscribe?.();
|
|
110472
110944
|
this.#unsubscribe = null;
|
|
110473
110945
|
this.#offRejoin?.();
|
|
@@ -110567,19 +111039,27 @@ var MeshNode = class {
|
|
|
110567
111039
|
staticPub: engine.localStaticPub(),
|
|
110568
111040
|
port: () => this.#port,
|
|
110569
111041
|
epoch: () => engine.policyEpoch(),
|
|
110570
|
-
onPeer: (staticPub, address, port) => this.#learnLanPeer(staticPub, address, port)
|
|
111042
|
+
onPeer: (staticPub, address, port, epoch2) => this.#learnLanPeer(staticPub, address, port, epoch2)
|
|
110571
111043
|
});
|
|
110572
111044
|
this.#lan.start();
|
|
110573
111045
|
} catch {
|
|
110574
111046
|
this.#lan = null;
|
|
110575
111047
|
}
|
|
110576
111048
|
}
|
|
110577
|
-
/** A beacon arrived. Treated exactly like a relay hint — a candidate, not a fact.
|
|
110578
|
-
|
|
111049
|
+
/** A beacon arrived. Treated exactly like a relay hint — a candidate, not a fact.
|
|
111050
|
+
*
|
|
111051
|
+
* Including its EPOCH. The beacon has always carried one (`lan.ts`: "port(2) | epoch(8)")
|
|
111052
|
+
* for the same reason the relay hint does — so a peer that is behind can be brought up
|
|
111053
|
+
* to date — and, like the relay hint's, it was thrown away here. Two laptops on one
|
|
111054
|
+
* Wi-Fi with the internet down are the demonstration that the overlay is not
|
|
111055
|
+
* relay-dependent; without this they would find each other and then never agree on who
|
|
111056
|
+
* else exists. */
|
|
111057
|
+
#learnLanPeer(staticPub, address, port, epoch2 = 0) {
|
|
110579
111058
|
const engine = this.#engine;
|
|
110580
111059
|
if (!engine)
|
|
110581
111060
|
return;
|
|
110582
111061
|
const hex6 = staticPub.toString("hex");
|
|
111062
|
+
this.#offerBundleTo(hex6, epoch2);
|
|
110583
111063
|
try {
|
|
110584
111064
|
if (!this.#peers.has(hex6)) {
|
|
110585
111065
|
engine.addPeer(staticPub, 0, Buffer.alloc(16));
|
|
@@ -110701,6 +111181,47 @@ var MeshNode = class {
|
|
|
110701
111181
|
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110702
111182
|
}
|
|
110703
111183
|
}
|
|
111184
|
+
/**
|
|
111185
|
+
* Ask the server for current policy, and adopt it if it is newer.
|
|
111186
|
+
*
|
|
111187
|
+
* The one path that can deliver an EVICTION. Gossip only ever moves a network to the
|
|
111188
|
+
* newest bundle some connected node already holds, and after an eviction no node holds
|
|
111189
|
+
* the new one — so without this, "remove that laptop" changed a database row and nothing
|
|
111190
|
+
* else until somebody happened to join.
|
|
111191
|
+
*
|
|
111192
|
+
* Applied through exactly the same steps as a gossiped bundle, deliberately: the engine
|
|
111193
|
+
* verifies it against genesis (so a hostile server cannot widen policy any more than a
|
|
111194
|
+
* hostile relay can), `#stopIfRevoked` reads our own serial out of it, it is cached to
|
|
111195
|
+
* disk, and the offer ledger resets so our peers hear about it too. That last part is
|
|
111196
|
+
* what makes one node's poll benefit the whole network.
|
|
111197
|
+
*/
|
|
111198
|
+
async #refreshBundle() {
|
|
111199
|
+
const engine = this.#engine;
|
|
111200
|
+
const id = this.#identity;
|
|
111201
|
+
if (!engine || !id?.sigPrivate)
|
|
111202
|
+
return;
|
|
111203
|
+
const meshDir2 = meshDirNameFromWireId(engine.meshId());
|
|
111204
|
+
const origin = (meshDir2 ? readLocal(meshDir2)?.origin : void 0) ?? readCredentials()?.apiOrigin;
|
|
111205
|
+
if (!origin)
|
|
111206
|
+
return;
|
|
111207
|
+
const got = await fetchBundle({
|
|
111208
|
+
origin,
|
|
111209
|
+
genesisFp: engine.meshId(),
|
|
111210
|
+
staticPub: Buffer.from(engine.localStaticPub()).toString("hex"),
|
|
111211
|
+
sigPrivate: id.sigPrivate
|
|
111212
|
+
});
|
|
111213
|
+
if (!got.bundle)
|
|
111214
|
+
return;
|
|
111215
|
+
try {
|
|
111216
|
+
engine.setBundle(Buffer.from(got.bundle), Date.now());
|
|
111217
|
+
} catch {
|
|
111218
|
+
return;
|
|
111219
|
+
}
|
|
111220
|
+
this.#stopIfRevoked(engine);
|
|
111221
|
+
cacheBundle(got.bundle, meshDir2 ?? void 0);
|
|
111222
|
+
this.#bundle = got.bundle;
|
|
111223
|
+
this.#bundleOffered.reset();
|
|
111224
|
+
}
|
|
110704
111225
|
/**
|
|
110705
111226
|
* Offer our policy bundle to a peer whose epoch is older than ours.
|
|
110706
111227
|
*
|
|
@@ -110795,10 +111316,12 @@ var MeshNode = class {
|
|
|
110795
111316
|
/** Flush everything the engine wants to send, and absorb its events. */
|
|
110796
111317
|
#drain() {
|
|
110797
111318
|
const engine = this.#engine;
|
|
110798
|
-
|
|
110799
|
-
if (!engine || !sock)
|
|
111319
|
+
if (!engine)
|
|
110800
111320
|
return;
|
|
111321
|
+
const sock = this.#sock;
|
|
110801
111322
|
for (; ; ) {
|
|
111323
|
+
if (!sock)
|
|
111324
|
+
break;
|
|
110802
111325
|
const item = engine.pollSend();
|
|
110803
111326
|
if (!item)
|
|
110804
111327
|
break;
|
|
@@ -110946,148 +111469,6 @@ function meshManager() {
|
|
|
110946
111469
|
return singleton3;
|
|
110947
111470
|
}
|
|
110948
111471
|
|
|
110949
|
-
// ../../packages/host-core/dist/mesh/netd-client.js
|
|
110950
|
-
import { connect as connect2 } from "node:net";
|
|
110951
|
-
import { platform as platform3 } from "node:process";
|
|
110952
|
-
var NETD_WIRE_VERSION = 1;
|
|
110953
|
-
var MAX_LINE = 1024 * 1024;
|
|
110954
|
-
var TIMEOUT_MS3 = 15e3;
|
|
110955
|
-
function netdEndpoint() {
|
|
110956
|
-
if (platform3 === "win32")
|
|
110957
|
-
return "\\\\.\\pipe\\tesseract-netd";
|
|
110958
|
-
if (platform3 === "darwin")
|
|
110959
|
-
return "/var/run/tesseract-netd.sock";
|
|
110960
|
-
return "/run/tesseract-netd.sock";
|
|
110961
|
-
}
|
|
110962
|
-
function endpointOverride() {
|
|
110963
|
-
return process.env.CCB_NETD_SOCKET ?? null;
|
|
110964
|
-
}
|
|
110965
|
-
function fail2(code, detail) {
|
|
110966
|
-
return { ok: false, code, detail };
|
|
110967
|
-
}
|
|
110968
|
-
async function call(line) {
|
|
110969
|
-
const endpoint2 = endpointOverride() ?? netdEndpoint();
|
|
110970
|
-
return new Promise((resolve16) => {
|
|
110971
|
-
let settled = false;
|
|
110972
|
-
const done = (r) => {
|
|
110973
|
-
if (settled)
|
|
110974
|
-
return;
|
|
110975
|
-
settled = true;
|
|
110976
|
-
try {
|
|
110977
|
-
sock.destroy();
|
|
110978
|
-
} catch {
|
|
110979
|
-
}
|
|
110980
|
-
resolve16(r);
|
|
110981
|
-
};
|
|
110982
|
-
let sock;
|
|
110983
|
-
try {
|
|
110984
|
-
sock = connect2(endpoint2);
|
|
110985
|
-
} catch (e) {
|
|
110986
|
-
return resolve16(fail2("not-installed", e instanceof Error ? e.message : String(e)));
|
|
110987
|
-
}
|
|
110988
|
-
const timer2 = setTimeout(() => {
|
|
110989
|
-
done(fail2("timeout", `no answer from the network helper in ${TIMEOUT_MS3}ms`));
|
|
110990
|
-
}, TIMEOUT_MS3);
|
|
110991
|
-
timer2.unref?.();
|
|
110992
|
-
sock.setTimeout(TIMEOUT_MS3);
|
|
110993
|
-
sock.on("timeout", () => {
|
|
110994
|
-
clearTimeout(timer2);
|
|
110995
|
-
done(fail2("timeout", "socket idle"));
|
|
110996
|
-
});
|
|
110997
|
-
sock.on("error", (e) => {
|
|
110998
|
-
clearTimeout(timer2);
|
|
110999
|
-
const absent = e.code === "ENOENT" || e.code === "ECONNREFUSED";
|
|
111000
|
-
done(fail2(absent ? "not-installed" : "io", e.message));
|
|
111001
|
-
});
|
|
111002
|
-
let buf = "";
|
|
111003
|
-
sock.on("data", (chunk) => {
|
|
111004
|
-
buf += chunk.toString("utf8");
|
|
111005
|
-
if (buf.length > MAX_LINE) {
|
|
111006
|
-
clearTimeout(timer2);
|
|
111007
|
-
done(fail2("protocol", "the helper sent an oversized line"));
|
|
111008
|
-
return;
|
|
111009
|
-
}
|
|
111010
|
-
const nl = buf.indexOf("\n");
|
|
111011
|
-
if (nl === -1)
|
|
111012
|
-
return;
|
|
111013
|
-
clearTimeout(timer2);
|
|
111014
|
-
done({ ok: true, line: buf.slice(0, nl) });
|
|
111015
|
-
});
|
|
111016
|
-
sock.on("close", () => {
|
|
111017
|
-
clearTimeout(timer2);
|
|
111018
|
-
done(fail2("protocol", "the helper closed the connection without answering"));
|
|
111019
|
-
});
|
|
111020
|
-
sock.on("connect", () => {
|
|
111021
|
-
sock.write(`${line}
|
|
111022
|
-
`);
|
|
111023
|
-
});
|
|
111024
|
-
});
|
|
111025
|
-
}
|
|
111026
|
-
function parse3(line) {
|
|
111027
|
-
let body;
|
|
111028
|
-
try {
|
|
111029
|
-
body = JSON.parse(line);
|
|
111030
|
-
} catch {
|
|
111031
|
-
return fail2("protocol", "the helper sent something that is not JSON");
|
|
111032
|
-
}
|
|
111033
|
-
if (typeof body !== "object" || body === null) {
|
|
111034
|
-
return fail2("protocol", "the helper sent something that is not an object");
|
|
111035
|
-
}
|
|
111036
|
-
const o = body;
|
|
111037
|
-
if (o.ok === false) {
|
|
111038
|
-
const code = typeof o.code === "string" ? o.code : "refused";
|
|
111039
|
-
const detail = typeof o.detail === "string" ? o.detail : "the helper refused";
|
|
111040
|
-
return fail2(code, detail);
|
|
111041
|
-
}
|
|
111042
|
-
if (o.ok !== true)
|
|
111043
|
-
return fail2("protocol", "the helper did not say whether it succeeded");
|
|
111044
|
-
return { ok: true, body: o };
|
|
111045
|
-
}
|
|
111046
|
-
async function request(line) {
|
|
111047
|
-
const r = await call(line);
|
|
111048
|
-
return r.ok ? parse3(r.line) : r;
|
|
111049
|
-
}
|
|
111050
|
-
function hex4(b) {
|
|
111051
|
-
return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
111052
|
-
}
|
|
111053
|
-
async function netdHello() {
|
|
111054
|
-
const r = await request(JSON.stringify({ op: "hello", wireVersion: NETD_WIRE_VERSION }));
|
|
111055
|
-
if (!r.ok)
|
|
111056
|
-
return r;
|
|
111057
|
-
const v = r.body.wireVersion;
|
|
111058
|
-
if (typeof v !== "number")
|
|
111059
|
-
return fail2("protocol", "the helper did not report a wire version");
|
|
111060
|
-
if (v !== NETD_WIRE_VERSION) {
|
|
111061
|
-
return fail2("wire-version", `the helper speaks ${v}, this build speaks ${NETD_WIRE_VERSION}`);
|
|
111062
|
-
}
|
|
111063
|
-
return { ok: true, wireVersion: v };
|
|
111064
|
-
}
|
|
111065
|
-
async function netdStatus() {
|
|
111066
|
-
const r = await request(JSON.stringify({ op: "status" }));
|
|
111067
|
-
if (!r.ok)
|
|
111068
|
-
return r;
|
|
111069
|
-
const meshes = Array.isArray(r.body.meshes) ? r.body.meshes.filter((m) => typeof m === "string") : [];
|
|
111070
|
-
const iface = typeof r.body.interface === "string" ? r.body.interface : null;
|
|
111071
|
-
return { ok: true, meshes, interface: iface };
|
|
111072
|
-
}
|
|
111073
|
-
async function netdUp(args) {
|
|
111074
|
-
const r = await request(JSON.stringify({
|
|
111075
|
-
op: "up",
|
|
111076
|
-
meshId: args.meshId,
|
|
111077
|
-
genesis: hex4(args.genesis),
|
|
111078
|
-
cert: hex4(args.cert),
|
|
111079
|
-
fullTunnel: args.fullTunnel === true
|
|
111080
|
-
}));
|
|
111081
|
-
return r.ok ? { ok: true } : r;
|
|
111082
|
-
}
|
|
111083
|
-
async function netdDown(meshId) {
|
|
111084
|
-
const r = await request(JSON.stringify({ op: "down", meshId }));
|
|
111085
|
-
return r.ok ? { ok: true } : r;
|
|
111086
|
-
}
|
|
111087
|
-
async function netdAvailable() {
|
|
111088
|
-
return (await netdHello()).ok;
|
|
111089
|
-
}
|
|
111090
|
-
|
|
111091
111472
|
// ../../packages/host-core/dist/mesh/route-sync.js
|
|
111092
111473
|
async function syncRoutes(running2, log9 = () => {
|
|
111093
111474
|
}) {
|
|
@@ -111116,7 +111497,14 @@ async function syncRoutes(running2, log9 = () => {
|
|
|
111116
111497
|
// The per-machine choice, and `=== true` rather than a truthiness check: an absent or
|
|
111117
111498
|
// malformed field must read as NO. netd unions this across meshes itself — any mesh
|
|
111118
111499
|
// asking for a full tunnel makes it one for the machine — so this stays per mesh here.
|
|
111119
|
-
fullTunnel: readLocal(meshId)?.fullTunnel === true
|
|
111500
|
+
fullTunnel: readLocal(meshId)?.fullTunnel === true,
|
|
111501
|
+
// THE KEY, and the bundle. With these netd runs the node — the data plane — rather
|
|
111502
|
+
// than only pointing routes at a device nothing reads. The crate's own doc always
|
|
111503
|
+
// described the enrolment as "a genesis block, a certificate and a key"; this is the
|
|
111504
|
+
// first caller to send the third. Over the helper's authenticated socket, to the one
|
|
111505
|
+
// process on the machine that already holds the device the traffic goes into.
|
|
111506
|
+
staticPrivate: identity.staticPrivate,
|
|
111507
|
+
...identity.bundle ? { bundle: identity.bundle } : {}
|
|
111120
111508
|
});
|
|
111121
111509
|
if (r.ok) {
|
|
111122
111510
|
out.up.push(meshId);
|
|
@@ -111142,22 +111530,63 @@ async function syncRoutes(running2, log9 = () => {
|
|
|
111142
111530
|
}
|
|
111143
111531
|
|
|
111144
111532
|
// ../../packages/host-core/dist/mesh/start-meshes.js
|
|
111145
|
-
|
|
111533
|
+
var ROUTE_RETRY_MS = 6e4;
|
|
111534
|
+
function startMeshes(log9, opts = {}) {
|
|
111146
111535
|
const running2 = startNodes(log9);
|
|
111147
|
-
|
|
111536
|
+
const retryMs = opts.retryMs ?? ROUTE_RETRY_MS;
|
|
111537
|
+
let timer2 = null;
|
|
111538
|
+
let stopped2 = false;
|
|
111539
|
+
let lastSummary = "";
|
|
111540
|
+
const attempt = async () => {
|
|
111541
|
+
let r;
|
|
111542
|
+
try {
|
|
111543
|
+
r = await syncRoutes(running2, log9);
|
|
111544
|
+
} catch (e) {
|
|
111545
|
+
log9(`routes: sync threw \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
111546
|
+
return false;
|
|
111547
|
+
}
|
|
111148
111548
|
if (r.helperAbsent) {
|
|
111149
|
-
|
|
111150
|
-
|
|
111549
|
+
const msg = "routes: the network helper is not installed \u2014 the overlay carries no traffic yet";
|
|
111550
|
+
if (msg !== lastSummary)
|
|
111551
|
+
log9(msg);
|
|
111552
|
+
lastSummary = msg;
|
|
111553
|
+
return false;
|
|
111151
111554
|
}
|
|
111152
111555
|
if (r.up.length)
|
|
111153
111556
|
log9(`routes: installed for ${r.up.join(", ")}`);
|
|
111154
111557
|
if (r.down.length)
|
|
111155
111558
|
log9(`routes: removed for ${r.down.join(", ")}`);
|
|
111156
|
-
|
|
111157
|
-
|
|
111158
|
-
|
|
111159
|
-
|
|
111559
|
+
const failures2 = r.failed.map((f) => `routes: ${f.meshId} refused \u2014 ${f.reason}`).join("\n");
|
|
111560
|
+
if (failures2 && failures2 !== lastSummary)
|
|
111561
|
+
log9(failures2);
|
|
111562
|
+
lastSummary = failures2;
|
|
111563
|
+
return r.failed.length === 0;
|
|
111564
|
+
};
|
|
111565
|
+
const schedule = () => {
|
|
111566
|
+
if (stopped2 || running2.length === 0)
|
|
111567
|
+
return;
|
|
111568
|
+
timer2 = setTimeout(() => {
|
|
111569
|
+
timer2 = null;
|
|
111570
|
+
void attempt().then((done) => {
|
|
111571
|
+
if (!done)
|
|
111572
|
+
schedule();
|
|
111573
|
+
});
|
|
111574
|
+
}, retryMs);
|
|
111575
|
+
timer2.unref?.();
|
|
111576
|
+
};
|
|
111577
|
+
void attempt().then((done) => {
|
|
111578
|
+
if (!done)
|
|
111579
|
+
schedule();
|
|
111160
111580
|
});
|
|
111581
|
+
return {
|
|
111582
|
+
stop() {
|
|
111583
|
+
stopped2 = true;
|
|
111584
|
+
if (timer2) {
|
|
111585
|
+
clearTimeout(timer2);
|
|
111586
|
+
timer2 = null;
|
|
111587
|
+
}
|
|
111588
|
+
}
|
|
111589
|
+
};
|
|
111161
111590
|
}
|
|
111162
111591
|
function startNodes(log9) {
|
|
111163
111592
|
const ids = listMeshIds();
|
|
@@ -112487,7 +112916,7 @@ function appendRdeskAudit(e) {
|
|
|
112487
112916
|
|
|
112488
112917
|
// ../../packages/host-core/dist/fileprovider-bridge.js
|
|
112489
112918
|
init_managed_spawn();
|
|
112490
|
-
import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync37, rmSync as rmSync8, existsSync as
|
|
112919
|
+
import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync37, rmSync as rmSync8, existsSync as existsSync35 } from "node:fs";
|
|
112491
112920
|
import { homedir as homedir10 } from "node:os";
|
|
112492
112921
|
import { join as join73 } from "node:path";
|
|
112493
112922
|
init_safe_kill();
|
|
@@ -112658,7 +113087,7 @@ function stopFileProviderBridge() {
|
|
|
112658
113087
|
|
|
112659
113088
|
// ../../packages/host-core/dist/vault/autofill-bridge.js
|
|
112660
113089
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
112661
|
-
import { existsSync as
|
|
113090
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync38, writeFileSync as writeFileSync37, rmSync as rmSync9 } from "node:fs";
|
|
112662
113091
|
import { homedir as homedir11 } from "node:os";
|
|
112663
113092
|
import { join as join74 } from "node:path";
|
|
112664
113093
|
|
|
@@ -112733,7 +113162,7 @@ function writeBridgeInfo(port, token3, log9) {
|
|
|
112733
113162
|
return;
|
|
112734
113163
|
const containerData = appexContainerData();
|
|
112735
113164
|
try {
|
|
112736
|
-
if (!
|
|
113165
|
+
if (!existsSync36(containerData)) {
|
|
112737
113166
|
if (!infoLoggedOnce) {
|
|
112738
113167
|
infoLoggedOnce = true;
|
|
112739
113168
|
log9("autofill bridge-info SKIP: no appex container yet at", containerData);
|
|
@@ -112982,7 +113411,7 @@ function createNodePowerController() {
|
|
|
112982
113411
|
|
|
112983
113412
|
// ../../packages/host-core/dist/native-host.js
|
|
112984
113413
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
112985
|
-
import { chmodSync as chmodSync6, existsSync as
|
|
113414
|
+
import { chmodSync as chmodSync6, existsSync as existsSync37, mkdirSync as mkdirSync39, writeFileSync as writeFileSync38 } from "node:fs";
|
|
112986
113415
|
import { homedir as homedir12, platform as platform5 } from "node:os";
|
|
112987
113416
|
import { dirname as dirname34, join as join75, resolve as resolve12 } from "node:path";
|
|
112988
113417
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
@@ -113013,7 +113442,7 @@ function resolveBridge(log9) {
|
|
|
113013
113442
|
} catch {
|
|
113014
113443
|
}
|
|
113015
113444
|
for (const c of candidates)
|
|
113016
|
-
if (c &&
|
|
113445
|
+
if (c && existsSync37(c))
|
|
113017
113446
|
return c;
|
|
113018
113447
|
log9("companion native-host: bridge not found; skipping registration (looked in", candidates.filter(Boolean).join(" , "), ")");
|
|
113019
113448
|
return null;
|
|
@@ -113055,7 +113484,7 @@ function registerNativeHost(opts) {
|
|
|
113055
113484
|
return registerWindows(opts.daemonDir, manifestJson, log9);
|
|
113056
113485
|
let wrote = 0;
|
|
113057
113486
|
for (const profile of browserProfileDirs()) {
|
|
113058
|
-
if (!
|
|
113487
|
+
if (!existsSync37(profile))
|
|
113059
113488
|
continue;
|
|
113060
113489
|
try {
|
|
113061
113490
|
const dir2 = join75(profile, "NativeMessagingHosts");
|
|
@@ -113091,7 +113520,7 @@ init_daemon_settings();
|
|
|
113091
113520
|
|
|
113092
113521
|
// ../../packages/host-core/dist/activity/activity-tracker.js
|
|
113093
113522
|
init_credentials();
|
|
113094
|
-
import { promises as fsp, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, existsSync as
|
|
113523
|
+
import { promises as fsp, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, existsSync as existsSync38 } from "node:fs";
|
|
113095
113524
|
import { join as join76 } from "node:path";
|
|
113096
113525
|
function activityProfilePath() {
|
|
113097
113526
|
return join76(daemonDir2(), "activity-profile.json");
|
|
@@ -113169,7 +113598,7 @@ function createActivityTracker(opts = {}) {
|
|
|
113169
113598
|
return;
|
|
113170
113599
|
const key2 = front.bundleId || front.name;
|
|
113171
113600
|
await ensureLoaded();
|
|
113172
|
-
if (profile && Object.keys(profile.apps).length && !
|
|
113601
|
+
if (profile && Object.keys(profile.apps).length && !existsSync38(activityProfilePath())) {
|
|
113173
113602
|
log9("activity profile cleared externally \u2014 resetting in-memory");
|
|
113174
113603
|
profile = { version: 1, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), apps: {} };
|
|
113175
113604
|
}
|
|
@@ -113402,7 +113831,7 @@ function backoff2() {
|
|
|
113402
113831
|
|
|
113403
113832
|
// ../../packages/host-core/dist/daemon-runtime.js
|
|
113404
113833
|
var daemonClipboardSync = null;
|
|
113405
|
-
var
|
|
113834
|
+
var REFRESH_INTERVAL_MS2 = 12 * 60 * 60 * 1e3;
|
|
113406
113835
|
async function runDaemon(opts = {}) {
|
|
113407
113836
|
const VERSION3 = opts.version ?? process.env.CCB_DAEMON_VERSION ?? "dev";
|
|
113408
113837
|
const TAG = opts.tag ?? "host-daemon";
|
|
@@ -113443,7 +113872,7 @@ async function runDaemon(opts = {}) {
|
|
|
113443
113872
|
function acquireLock2() {
|
|
113444
113873
|
const f = pidfile();
|
|
113445
113874
|
try {
|
|
113446
|
-
if (!
|
|
113875
|
+
if (!existsSync39(daemonDir2()))
|
|
113447
113876
|
mkdirSync41(daemonDir2(), { recursive: true, mode: 448 });
|
|
113448
113877
|
} catch {
|
|
113449
113878
|
}
|
|
@@ -113469,7 +113898,7 @@ async function runDaemon(opts = {}) {
|
|
|
113469
113898
|
function releaseLock() {
|
|
113470
113899
|
try {
|
|
113471
113900
|
const f = pidfile();
|
|
113472
|
-
if (
|
|
113901
|
+
if (existsSync39(f) && Number(readFileSync49(f, "utf-8").trim()) === process.pid)
|
|
113473
113902
|
unlinkSync6(f);
|
|
113474
113903
|
} catch {
|
|
113475
113904
|
}
|
|
@@ -113511,6 +113940,7 @@ async function runDaemon(opts = {}) {
|
|
|
113511
113940
|
}
|
|
113512
113941
|
}
|
|
113513
113942
|
let stopGatewayKeyRefresh = null;
|
|
113943
|
+
let meshRoutes = null;
|
|
113514
113944
|
let timer2 = null;
|
|
113515
113945
|
let identityWatch = null;
|
|
113516
113946
|
let refreshRetry = null;
|
|
@@ -113605,6 +114035,10 @@ async function runDaemon(opts = {}) {
|
|
|
113605
114035
|
stopGatewayKeyRefresh();
|
|
113606
114036
|
stopGatewayKeyRefresh = null;
|
|
113607
114037
|
}
|
|
114038
|
+
if (meshRoutes) {
|
|
114039
|
+
meshRoutes.stop();
|
|
114040
|
+
meshRoutes = null;
|
|
114041
|
+
}
|
|
113608
114042
|
try {
|
|
113609
114043
|
offRecovery?.();
|
|
113610
114044
|
offRecovery = null;
|
|
@@ -114296,7 +114730,7 @@ async function runDaemon(opts = {}) {
|
|
|
114296
114730
|
} catch {
|
|
114297
114731
|
}
|
|
114298
114732
|
try {
|
|
114299
|
-
startMeshes(log9);
|
|
114733
|
+
meshRoutes = startMeshes(log9);
|
|
114300
114734
|
} catch {
|
|
114301
114735
|
}
|
|
114302
114736
|
writeStatus2({ deviceId: c.deviceId, connected: true });
|
|
@@ -114575,7 +115009,7 @@ async function runDaemon(opts = {}) {
|
|
|
114575
115009
|
const daemonLogFile = join77(daemonDir2(), "daemon.log");
|
|
114576
115010
|
const capTimer = setInterval(() => {
|
|
114577
115011
|
try {
|
|
114578
|
-
if (
|
|
115012
|
+
if (existsSync39(daemonLogFile) && statSync14(daemonLogFile).size > DAEMON_LOG_CAP) {
|
|
114579
115013
|
const buf = readFileSync49(daemonLogFile, "utf-8");
|
|
114580
115014
|
const kept = `\u2026[daemon.log capped at ${(/* @__PURE__ */ new Date()).toISOString()}]\u2026
|
|
114581
115015
|
` + buf.slice(-DAEMON_LOG_CAP / 2);
|
|
@@ -114592,7 +115026,7 @@ async function runDaemon(opts = {}) {
|
|
|
114592
115026
|
startAutofillBridge(log9);
|
|
114593
115027
|
}
|
|
114594
115028
|
if (ownsMachine)
|
|
114595
|
-
startMeshes(log9);
|
|
115029
|
+
meshRoutes = startMeshes(log9);
|
|
114596
115030
|
if (ownsMachine) {
|
|
114597
115031
|
try {
|
|
114598
115032
|
stopGatewayKeyRefresh = startGatewayKeyRefresh();
|
|
@@ -114604,7 +115038,7 @@ async function runDaemon(opts = {}) {
|
|
|
114604
115038
|
await refresh();
|
|
114605
115039
|
timer2 = setInterval(() => {
|
|
114606
115040
|
void refresh();
|
|
114607
|
-
},
|
|
115041
|
+
}, REFRESH_INTERVAL_MS2);
|
|
114608
115042
|
}
|
|
114609
115043
|
|
|
114610
115044
|
// ../../packages/host-core/dist/host-daemon-entry.js
|
|
@@ -114714,7 +115148,7 @@ async function evictNode(args) {
|
|
|
114714
115148
|
const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}`, { method: "DELETE", body: {} });
|
|
114715
115149
|
return r.ok ? { ok: true, epoch: r.data.epoch } : r;
|
|
114716
115150
|
}
|
|
114717
|
-
async function enrolWith(requested, post) {
|
|
115151
|
+
async function enrolWith(requested, post, origin) {
|
|
114718
115152
|
const name = normaliseNodeName(requested);
|
|
114719
115153
|
if (!name) {
|
|
114720
115154
|
return fail3("bad-name", `"${requested}" cannot be a machine name \u2014 names are DNS labels, so letters, digits and hyphens only`);
|
|
@@ -114738,7 +115172,7 @@ async function enrolWith(requested, post) {
|
|
|
114738
115172
|
}
|
|
114739
115173
|
try {
|
|
114740
115174
|
saveMesh(meshId, { genesis, cert, staticPrivate, sigPrivate });
|
|
114741
|
-
writeLocal(meshId, { joinedAt: Date.now(), enabled: true });
|
|
115175
|
+
writeLocal(meshId, { joinedAt: Date.now(), enabled: true, ...origin ? { origin } : {} });
|
|
114742
115176
|
if (r.data.bundle) {
|
|
114743
115177
|
try {
|
|
114744
115178
|
cacheBundle(fromHexOrB64(r.data.bundle), meshId);
|
|
@@ -114760,16 +115194,24 @@ async function enrolWith(requested, post) {
|
|
|
114760
115194
|
};
|
|
114761
115195
|
}
|
|
114762
115196
|
async function enrol(args) {
|
|
114763
|
-
return enrolWith(
|
|
114764
|
-
|
|
114765
|
-
|
|
114766
|
-
|
|
115197
|
+
return enrolWith(
|
|
115198
|
+
args.name,
|
|
115199
|
+
(staticPub, sigPub, name) => call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes`, {
|
|
115200
|
+
method: "POST",
|
|
115201
|
+
body: { name, staticPub, sigPub, ...args.exitNode === true ? { exitNode: true } : {} }
|
|
115202
|
+
}),
|
|
115203
|
+
// This path is authenticated, so the origin is necessarily the signed-in one.
|
|
115204
|
+
resolveOrigin(void 0)
|
|
115205
|
+
);
|
|
114767
115206
|
}
|
|
114768
115207
|
async function joinWithToken(args) {
|
|
114769
|
-
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { token: args.token, name, staticPub, sigPub }));
|
|
115208
|
+
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { token: args.token, name, staticPub, sigPub }), resolveOrigin(args.origin));
|
|
115209
|
+
}
|
|
115210
|
+
function resolveOrigin(origin) {
|
|
115211
|
+
return origin ?? readCredentials()?.apiOrigin ?? void 0;
|
|
114770
115212
|
}
|
|
114771
115213
|
async function postJoin(origin, body) {
|
|
114772
|
-
const base = origin
|
|
115214
|
+
const base = resolveOrigin(origin);
|
|
114773
115215
|
if (!base) {
|
|
114774
115216
|
return fail3("not-signed-in", "this machine has never signed in \u2014 pass --origin https://\u2026 so it knows which server to ask");
|
|
114775
115217
|
}
|
|
@@ -114797,7 +115239,7 @@ async function postJoin(origin, body) {
|
|
|
114797
115239
|
return { ok: true, data: JSON.parse(text12) };
|
|
114798
115240
|
}
|
|
114799
115241
|
async function enrolWithCode(args) {
|
|
114800
|
-
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { code: args.code, name, staticPub, sigPub }));
|
|
115242
|
+
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { code: args.code, name, staticPub, sigPub }), resolveOrigin(args.origin));
|
|
114801
115243
|
}
|
|
114802
115244
|
async function rawPrivate(key2) {
|
|
114803
115245
|
const pkcs8 = new Uint8Array(await crypto.subtle.exportKey("pkcs8", key2));
|
|
@@ -114881,13 +115323,13 @@ init_credentials();
|
|
|
114881
115323
|
|
|
114882
115324
|
// ../../packages/host-core/dist/net-service/ensure-installed.js
|
|
114883
115325
|
import { execFile as execFile14 } from "node:child_process";
|
|
114884
|
-
import { existsSync as
|
|
115326
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
114885
115327
|
import { dirname as dirname36, join as join81 } from "node:path";
|
|
114886
115328
|
import { promisify as promisify10 } from "node:util";
|
|
114887
115329
|
|
|
114888
115330
|
// ../../packages/host-core/dist/net-service/launchd-system.js
|
|
114889
115331
|
import { spawn as spawn9 } from "node:child_process";
|
|
114890
|
-
import { existsSync as
|
|
115332
|
+
import { existsSync as existsSync40, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync41, rmSync as rmSync10, readFileSync as readFileSync50 } from "node:fs";
|
|
114891
115333
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
114892
115334
|
import { join as join78 } from "node:path";
|
|
114893
115335
|
|
|
@@ -115058,7 +115500,7 @@ ${plist}TESSERACT_PLIST_EOF`,
|
|
|
115058
115500
|
};
|
|
115059
115501
|
},
|
|
115060
115502
|
async state() {
|
|
115061
|
-
if (!
|
|
115503
|
+
if (!existsSync40(PLIST))
|
|
115062
115504
|
return { installed: false, running: false };
|
|
115063
115505
|
const owner = parseOwnerUid(readFileSync50(PLIST, "utf8"));
|
|
115064
115506
|
const running2 = await netdAvailable();
|
|
@@ -115078,7 +115520,7 @@ ${plist}TESSERACT_PLIST_EOF`,
|
|
|
115078
115520
|
|
|
115079
115521
|
// ../../packages/host-core/dist/net-service/systemd-system.js
|
|
115080
115522
|
import { spawn as spawn11 } from "node:child_process";
|
|
115081
|
-
import { existsSync as
|
|
115523
|
+
import { existsSync as existsSync41, readFileSync as readFileSync51 } from "node:fs";
|
|
115082
115524
|
|
|
115083
115525
|
// ../../packages/host-core/dist/service/exec.js
|
|
115084
115526
|
import { execFile as execFile11, spawn as spawn10 } from "node:child_process";
|
|
@@ -115221,7 +115663,7 @@ function makeSystemdSystem() {
|
|
|
115221
115663
|
return code === 0 ? { ok: true } : { ok: false, detail: `removing the helper failed (exit ${code})` };
|
|
115222
115664
|
},
|
|
115223
115665
|
async state() {
|
|
115224
|
-
if (!
|
|
115666
|
+
if (!existsSync41(UNIT_PATH))
|
|
115225
115667
|
return { installed: false, running: false };
|
|
115226
115668
|
const owner = parseOwnerUid(readFileSync51(UNIT_PATH, "utf8"));
|
|
115227
115669
|
const active = await tryRun("systemctl", ["is-active", UNIT]);
|
|
@@ -115484,7 +115926,7 @@ function makeNetService() {
|
|
|
115484
115926
|
}
|
|
115485
115927
|
|
|
115486
115928
|
// ../../packages/host-core/dist/net-service/netd-binary.js
|
|
115487
|
-
import { existsSync as
|
|
115929
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
115488
115930
|
import { dirname as dirname35, join as join80 } from "node:path";
|
|
115489
115931
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
115490
115932
|
function netdBinaryName() {
|
|
@@ -115492,7 +115934,7 @@ function netdBinaryName() {
|
|
|
115492
115934
|
}
|
|
115493
115935
|
function override2() {
|
|
115494
115936
|
const p = process.env.CCB_NETD_BIN;
|
|
115495
|
-
return p &&
|
|
115937
|
+
return p && existsSync42(p) ? p : null;
|
|
115496
115938
|
}
|
|
115497
115939
|
function netdBinaryPath() {
|
|
115498
115940
|
const fromEnv = override2();
|
|
@@ -115519,7 +115961,7 @@ function netdBinaryPath() {
|
|
|
115519
115961
|
candidates.push(join80(process.cwd(), "crates", "target", "release", name));
|
|
115520
115962
|
for (const c of candidates) {
|
|
115521
115963
|
try {
|
|
115522
|
-
if (
|
|
115964
|
+
if (existsSync42(c))
|
|
115523
115965
|
return c;
|
|
115524
115966
|
} catch {
|
|
115525
115967
|
}
|
|
@@ -115561,7 +116003,7 @@ async function ensureNetHelperInstalled() {
|
|
|
115561
116003
|
if (st.installed && !mismatched)
|
|
115562
116004
|
return { ok: true, already: true };
|
|
115563
116005
|
const exec2 = netdBinaryPath();
|
|
115564
|
-
if (exec2 && process.platform === "win32" && !
|
|
116006
|
+
if (exec2 && process.platform === "win32" && !existsSync43(join81(dirname36(exec2), "wintun.dll"))) {
|
|
115565
116007
|
return {
|
|
115566
116008
|
ok: false,
|
|
115567
116009
|
reason: "no-binary",
|
|
@@ -115613,7 +116055,7 @@ import { platform as platform6 } from "node:os";
|
|
|
115613
116055
|
|
|
115614
116056
|
// ../../packages/host-core/dist/service/launchd.js
|
|
115615
116057
|
init_credentials();
|
|
115616
|
-
import { writeFileSync as writeFileSync43, existsSync as
|
|
116058
|
+
import { writeFileSync as writeFileSync43, existsSync as existsSync44, mkdirSync as mkdirSync42, unlinkSync as unlinkSync7 } from "node:fs";
|
|
115617
116059
|
import { dirname as dirname37, join as join82 } from "node:path";
|
|
115618
116060
|
import { homedir as homedir13, userInfo as userInfo2 } from "node:os";
|
|
115619
116061
|
function xml2(s) {
|
|
@@ -115668,6 +116110,36 @@ ${env}
|
|
|
115668
116110
|
</plist>
|
|
115669
116111
|
`;
|
|
115670
116112
|
}
|
|
116113
|
+
const loaded = async () => {
|
|
116114
|
+
try {
|
|
116115
|
+
await run5("launchctl", ["print", serviceTarget()]);
|
|
116116
|
+
return true;
|
|
116117
|
+
} catch {
|
|
116118
|
+
return false;
|
|
116119
|
+
}
|
|
116120
|
+
};
|
|
116121
|
+
const untilGone = async () => {
|
|
116122
|
+
for (let i = 0; i < 25; i++) {
|
|
116123
|
+
if (!await loaded())
|
|
116124
|
+
return;
|
|
116125
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
116126
|
+
}
|
|
116127
|
+
};
|
|
116128
|
+
const bootstrapWithRetry = async () => {
|
|
116129
|
+
let last;
|
|
116130
|
+
for (let i = 0; i < 5; i++) {
|
|
116131
|
+
try {
|
|
116132
|
+
await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]);
|
|
116133
|
+
return;
|
|
116134
|
+
} catch (e) {
|
|
116135
|
+
last = e;
|
|
116136
|
+
if (await loaded())
|
|
116137
|
+
return;
|
|
116138
|
+
await new Promise((r) => setTimeout(r, 300 * (i + 1)));
|
|
116139
|
+
}
|
|
116140
|
+
}
|
|
116141
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
116142
|
+
};
|
|
115671
116143
|
return {
|
|
115672
116144
|
async install(spec) {
|
|
115673
116145
|
mkdirSync42(workDirOf(spec), { recursive: true });
|
|
@@ -115676,16 +116148,20 @@ ${env}
|
|
|
115676
116148
|
writeFileSync43(plistPath(), buildPlist2(spec));
|
|
115677
116149
|
await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
|
|
115678
116150
|
});
|
|
115679
|
-
await
|
|
116151
|
+
await untilGone();
|
|
116152
|
+
await bootstrapWithRetry();
|
|
115680
116153
|
await run5("launchctl", ["enable", serviceTarget()]).catch(() => {
|
|
115681
116154
|
});
|
|
115682
116155
|
await run5("launchctl", ["kickstart", "-k", serviceTarget()]).catch(() => {
|
|
115683
116156
|
});
|
|
116157
|
+
if (!await loaded()) {
|
|
116158
|
+
throw new Error(`the service ${label} is not loaded after install \u2014 check \`launchctl print ${serviceTarget()}\``);
|
|
116159
|
+
}
|
|
115684
116160
|
},
|
|
115685
116161
|
async uninstall() {
|
|
115686
116162
|
await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
|
|
115687
116163
|
});
|
|
115688
|
-
if (
|
|
116164
|
+
if (existsSync44(plistPath())) {
|
|
115689
116165
|
try {
|
|
115690
116166
|
unlinkSync7(plistPath());
|
|
115691
116167
|
} catch {
|
|
@@ -115696,7 +116172,7 @@ ${env}
|
|
|
115696
116172
|
await this.install(spec);
|
|
115697
116173
|
},
|
|
115698
116174
|
async isInstalled() {
|
|
115699
|
-
return
|
|
116175
|
+
return existsSync44(plistPath());
|
|
115700
116176
|
},
|
|
115701
116177
|
async start() {
|
|
115702
116178
|
await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]).catch(() => {
|
|
@@ -115713,7 +116189,7 @@ ${env}
|
|
|
115713
116189
|
},
|
|
115714
116190
|
async logs(follow) {
|
|
115715
116191
|
const f = logFile();
|
|
115716
|
-
if (!
|
|
116192
|
+
if (!existsSync44(f)) {
|
|
115717
116193
|
console.log(`No log yet at ${f} \u2014 has the service started?`);
|
|
115718
116194
|
return;
|
|
115719
116195
|
}
|
|
@@ -115724,7 +116200,7 @@ ${env}
|
|
|
115724
116200
|
|
|
115725
116201
|
// ../../packages/host-core/dist/service/systemd.js
|
|
115726
116202
|
init_credentials();
|
|
115727
|
-
import { writeFileSync as writeFileSync44, existsSync as
|
|
116203
|
+
import { writeFileSync as writeFileSync44, existsSync as existsSync45, mkdirSync as mkdirSync43, unlinkSync as unlinkSync8 } from "node:fs";
|
|
115728
116204
|
import { dirname as dirname38, join as join83 } from "node:path";
|
|
115729
116205
|
import { homedir as homedir14, userInfo as userInfo3 } from "node:os";
|
|
115730
116206
|
function unitVal2(v) {
|
|
@@ -115780,7 +116256,7 @@ WantedBy=default.target
|
|
|
115780
116256
|
async uninstall() {
|
|
115781
116257
|
await run5("systemctl", ["--user", "disable", "--now", unit]).catch(() => {
|
|
115782
116258
|
});
|
|
115783
|
-
if (
|
|
116259
|
+
if (existsSync45(unitPath())) {
|
|
115784
116260
|
try {
|
|
115785
116261
|
unlinkSync8(unitPath());
|
|
115786
116262
|
} catch {
|
|
@@ -115793,7 +116269,7 @@ WantedBy=default.target
|
|
|
115793
116269
|
await this.install(spec);
|
|
115794
116270
|
},
|
|
115795
116271
|
async isInstalled() {
|
|
115796
|
-
return
|
|
116272
|
+
return existsSync45(unitPath());
|
|
115797
116273
|
},
|
|
115798
116274
|
async start() {
|
|
115799
116275
|
await run5("systemctl", ["--user", "start", unit]);
|
|
@@ -115806,7 +116282,7 @@ WantedBy=default.target
|
|
|
115806
116282
|
},
|
|
115807
116283
|
async logs(follow) {
|
|
115808
116284
|
const f = join83(daemonDir2(), "daemon.log");
|
|
115809
|
-
if (
|
|
116285
|
+
if (existsSync45(f)) {
|
|
115810
116286
|
await runInherit("tail", follow ? ["-f", f] : ["-n", "200", f]);
|
|
115811
116287
|
return;
|
|
115812
116288
|
}
|
|
@@ -115818,8 +116294,20 @@ WantedBy=default.target
|
|
|
115818
116294
|
|
|
115819
116295
|
// ../../packages/host-core/dist/service/windows.js
|
|
115820
116296
|
init_credentials();
|
|
115821
|
-
import { writeFileSync as writeFileSync45, existsSync as
|
|
116297
|
+
import { writeFileSync as writeFileSync45, existsSync as existsSync46, mkdirSync as mkdirSync44, unlinkSync as unlinkSync9, readFileSync as readFileSync52 } from "node:fs";
|
|
115822
116298
|
import { dirname as dirname39, join as join84 } from "node:path";
|
|
116299
|
+
function publishedDaemonPid(dir2) {
|
|
116300
|
+
for (const f of ["status.json", "daemon.lock"]) {
|
|
116301
|
+
try {
|
|
116302
|
+
const raw = readFileSync52(join84(dir2, f), "utf-8");
|
|
116303
|
+
const pid = f === "status.json" ? Number(JSON.parse(raw).pid) : Number(raw.trim());
|
|
116304
|
+
if (Number.isInteger(pid) && pid > 0)
|
|
116305
|
+
return pid;
|
|
116306
|
+
} catch {
|
|
116307
|
+
}
|
|
116308
|
+
}
|
|
116309
|
+
return null;
|
|
116310
|
+
}
|
|
115823
116311
|
function makeWindowsTask(instanceId) {
|
|
115824
116312
|
const suffix = instanceSuffix(instanceId);
|
|
115825
116313
|
const task = `Fineguide\\TesseractHost${suffix ? `-${suffix}` : ""}`;
|
|
@@ -115851,14 +116339,20 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
|
|
|
115851
116339
|
async uninstall() {
|
|
115852
116340
|
await run5("schtasks", ["/Delete", "/TN", task, "/F"]).catch(() => {
|
|
115853
116341
|
});
|
|
115854
|
-
if (
|
|
116342
|
+
if (existsSync46(wrapperPath())) {
|
|
115855
116343
|
try {
|
|
115856
116344
|
unlinkSync9(wrapperPath());
|
|
115857
116345
|
} catch {
|
|
115858
116346
|
}
|
|
115859
116347
|
}
|
|
115860
116348
|
},
|
|
116349
|
+
// STOP FIRST. `install` alone re-creates the task and runs it, which on Windows spawns a
|
|
116350
|
+
// SECOND daemon beside the one that is still running (see stop()); the newcomer finds the
|
|
116351
|
+
// pid lock held and stands down, so "restart" restarted nothing — the old process kept
|
|
116352
|
+
// running the old code. That is how a machine upgraded to a fixed CLI kept exhibiting the
|
|
116353
|
+
// bug the upgrade fixed, and how `tesseract-agent restart` reported success while doing it.
|
|
115861
116354
|
async restart(spec) {
|
|
116355
|
+
await this.stop();
|
|
115862
116356
|
await this.install(spec);
|
|
115863
116357
|
},
|
|
115864
116358
|
async isInstalled() {
|
|
@@ -115872,16 +116366,54 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
|
|
|
115872
116366
|
async start() {
|
|
115873
116367
|
await run5("schtasks", ["/Run", "/TN", task]);
|
|
115874
116368
|
},
|
|
116369
|
+
/**
|
|
116370
|
+
* Stop the daemon. Not the task — the daemon.
|
|
116371
|
+
*
|
|
116372
|
+
* `schtasks /End` ends the TASK's process, and the task's process is the .cmd wrapper, which
|
|
116373
|
+
* exited the instant it ran `start "" /b` to detach the daemon. So /End ended a task that had
|
|
116374
|
+
* already finished, reported success, and the daemon ran on. Every `stop`, `restart` and
|
|
116375
|
+
* self-update on Windows has been a no-op against a running daemon since the wrapper was
|
|
116376
|
+
* written; observed directly as two node processes surviving stop, restart, and the task's
|
|
116377
|
+
* own /End, with start times from the original launch.
|
|
116378
|
+
*
|
|
116379
|
+
* The daemon publishes its own pid (status.json / daemon.lock), and that is what gets ended.
|
|
116380
|
+
* Its PARENT is ended instead when the parent is the CLI supervisor (`cli.js run`), because
|
|
116381
|
+
* killing only the worker makes the supervisor respawn it; `/T` takes the whole tree either
|
|
116382
|
+
* way. The parent is checked by command line before being touched: the lock can be held by a
|
|
116383
|
+
* process that is not ours to kill — the desktop app owning the machine — and a supervisor
|
|
116384
|
+
* that is not `cli.js` is left alone, worker only.
|
|
116385
|
+
*
|
|
116386
|
+
* Best-effort throughout, like the other controllers' stop: a daemon that is already gone
|
|
116387
|
+
* is the desired state, not an error.
|
|
116388
|
+
*/
|
|
115875
116389
|
async stop() {
|
|
115876
116390
|
await run5("schtasks", ["/End", "/TN", task]).catch(() => {
|
|
115877
116391
|
});
|
|
116392
|
+
const pid = publishedDaemonPid(daemonDir2());
|
|
116393
|
+
if (pid === null)
|
|
116394
|
+
return;
|
|
116395
|
+
let target = pid;
|
|
116396
|
+
try {
|
|
116397
|
+
const { stdout } = await run5("powershell", [
|
|
116398
|
+
"-NoProfile",
|
|
116399
|
+
"-Command",
|
|
116400
|
+
`$p = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}"; if ($p) { $pp = Get-CimInstance Win32_Process -Filter "ProcessId = $($p.ParentProcessId)"; if ($pp) { "$($pp.ProcessId)|$($pp.CommandLine)" } }`
|
|
116401
|
+
]);
|
|
116402
|
+
const [ppidRaw, cmd = ""] = String(stdout).trim().split("|");
|
|
116403
|
+
const ppid = Number(ppidRaw);
|
|
116404
|
+
if (Number.isInteger(ppid) && ppid > 0 && /cli\.js["']?\s+run\b/.test(cmd))
|
|
116405
|
+
target = ppid;
|
|
116406
|
+
} catch {
|
|
116407
|
+
}
|
|
116408
|
+
await run5("taskkill", ["/pid", String(target), "/T", "/F"]).catch(() => {
|
|
116409
|
+
});
|
|
115878
116410
|
},
|
|
115879
116411
|
async status() {
|
|
115880
116412
|
await runInherit("schtasks", ["/Query", "/TN", task, "/V", "/FO", "LIST"]);
|
|
115881
116413
|
},
|
|
115882
116414
|
async logs(follow) {
|
|
115883
116415
|
const f = logFile();
|
|
115884
|
-
if (!
|
|
116416
|
+
if (!existsSync46(f)) {
|
|
115885
116417
|
console.log(`No log yet at ${f} \u2014 has the task run?`);
|
|
115886
116418
|
return;
|
|
115887
116419
|
}
|
|
@@ -115913,7 +116445,7 @@ init_safe_kill();
|
|
|
115913
116445
|
// src/auth.ts
|
|
115914
116446
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
115915
116447
|
import { randomUUID as randomUUID30 } from "node:crypto";
|
|
115916
|
-
import { existsSync as
|
|
116448
|
+
import { existsSync as existsSync47, rmSync as rmSync12 } from "node:fs";
|
|
115917
116449
|
import { join as join85 } from "node:path";
|
|
115918
116450
|
|
|
115919
116451
|
// src/config.ts
|
|
@@ -116116,7 +116648,7 @@ async function logout() {
|
|
|
116116
116648
|
for (const f of ["credentials.json", "status.json", "daemon.lock"]) {
|
|
116117
116649
|
try {
|
|
116118
116650
|
const p = join85(daemonDir2(), f);
|
|
116119
|
-
if (
|
|
116651
|
+
if (existsSync47(p)) rmSync12(p);
|
|
116120
116652
|
} catch {
|
|
116121
116653
|
}
|
|
116122
116654
|
}
|
|
@@ -116276,7 +116808,7 @@ function startSelfUpdater(current) {
|
|
|
116276
116808
|
// src/service.ts
|
|
116277
116809
|
import { join as join86 } from "node:path";
|
|
116278
116810
|
import { platform as platform7 } from "node:os";
|
|
116279
|
-
import { existsSync as
|
|
116811
|
+
import { existsSync as existsSync48, readFileSync as readFileSync53 } from "node:fs";
|
|
116280
116812
|
function controller(instanceId) {
|
|
116281
116813
|
const c = getServiceController(instanceId);
|
|
116282
116814
|
if (!c) {
|
|
@@ -116303,8 +116835,8 @@ var isAlive = (pid) => {
|
|
|
116303
116835
|
function runningDaemonInfo() {
|
|
116304
116836
|
const lock = join86(daemonDir2(), "daemon.lock");
|
|
116305
116837
|
try {
|
|
116306
|
-
if (!
|
|
116307
|
-
const pid = Number(
|
|
116838
|
+
if (!existsSync48(lock)) return null;
|
|
116839
|
+
const pid = Number(readFileSync53(lock, "utf-8").trim());
|
|
116308
116840
|
if (!pid || !isAlive(pid)) return null;
|
|
116309
116841
|
return { pid, device: readCredentials()?.deviceId };
|
|
116310
116842
|
} catch {
|
|
@@ -116338,7 +116870,7 @@ async function logs(instanceId, follow) {
|
|
|
116338
116870
|
}
|
|
116339
116871
|
|
|
116340
116872
|
// src/net.ts
|
|
116341
|
-
import { readFileSync as
|
|
116873
|
+
import { readFileSync as readFileSync55 } from "node:fs";
|
|
116342
116874
|
import { randomBytes as randomBytes11 } from "node:crypto";
|
|
116343
116875
|
import { hostname as hostname7 } from "node:os";
|
|
116344
116876
|
import { resolve as resolve14 } from "node:path";
|
|
@@ -116403,7 +116935,7 @@ function readOrDie(label, p) {
|
|
|
116403
116935
|
process.exit(1);
|
|
116404
116936
|
}
|
|
116405
116937
|
try {
|
|
116406
|
-
return new Uint8Array(
|
|
116938
|
+
return new Uint8Array(readFileSync55(resolve14(p)));
|
|
116407
116939
|
} catch (e) {
|
|
116408
116940
|
console.error(`net enroll: could not read --${label} ${p}: ${e instanceof Error ? e.message : e}`);
|
|
116409
116941
|
process.exit(1);
|
|
@@ -116475,6 +117007,9 @@ async function netCommand(rest, flags) {
|
|
|
116475
117007
|
const established = s.established ?? [];
|
|
116476
117008
|
const relayed = s.relayed ?? [];
|
|
116477
117009
|
console.log(`peers: ${s.peers ?? 0} known, ${established.length} with a live session`);
|
|
117010
|
+
if (typeof s.policyEpoch === "number") {
|
|
117011
|
+
console.log(`policy: epoch ${s.policyEpoch}${s.policyEpoch === 0 ? " \u2014 no policy yet, so NO traffic will pass" : ""}`);
|
|
117012
|
+
}
|
|
116478
117013
|
if (relayed.length) {
|
|
116479
117014
|
console.log(`relayed: ${relayed.length} (${relayed.join(", ")}) \u2014 these are NOT direct`);
|
|
116480
117015
|
} else if (established.length) {
|
|
@@ -116954,7 +117489,7 @@ async function netCommand(rest, flags) {
|
|
|
116954
117489
|
function pkgVersion() {
|
|
116955
117490
|
try {
|
|
116956
117491
|
const p = join88(dirname40(fileURLToPath8(import.meta.url)), "..", "package.json");
|
|
116957
|
-
return JSON.parse(
|
|
117492
|
+
return JSON.parse(readFileSync56(p, "utf8")).version ?? "0.0.0";
|
|
116958
117493
|
} catch {
|
|
116959
117494
|
return "0.0.0";
|
|
116960
117495
|
}
|
|
@@ -117200,7 +117735,7 @@ async function captureClaudeSubscription(flags) {
|
|
|
117200
117735
|
});
|
|
117201
117736
|
if (code !== 0) throw new Error(`Claude sign-in did not complete (exit ${code}).`);
|
|
117202
117737
|
const file2 = join88(home, ".credentials.json");
|
|
117203
|
-
if (
|
|
117738
|
+
if (existsSync50(file2)) return readFileSync56(file2, "utf8");
|
|
117204
117739
|
if (process.platform === "darwin") {
|
|
117205
117740
|
const value = execFileSync6("security", [
|
|
117206
117741
|
"find-generic-password",
|
|
@@ -117282,7 +117817,7 @@ async function runnerCommand(rest, flags) {
|
|
|
117282
117817
|
process.exit(1);
|
|
117283
117818
|
}
|
|
117284
117819
|
const oauthFilePath = typeof flags["oauth-file"] === "string" ? resolve15(flags["oauth-file"]) : void 0;
|
|
117285
|
-
const oauthAuthFile = oauthFilePath ?
|
|
117820
|
+
const oauthAuthFile = oauthFilePath ? readFileSync56(oauthFilePath, "utf8") : void 0;
|
|
117286
117821
|
if (oauthAuthFile) {
|
|
117287
117822
|
try {
|
|
117288
117823
|
JSON.parse(oauthAuthFile);
|