tesseract-agent 0.11.1 → 0.11.3
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
CHANGED
|
@@ -37920,6 +37920,9 @@ import { spawn as spawn2, execSync, execFileSync } from "node:child_process";
|
|
|
37920
37920
|
function setBrowserExtensionProbe(fn) {
|
|
37921
37921
|
browserExtensionConnected = fn;
|
|
37922
37922
|
}
|
|
37923
|
+
function isTurnBearingFrame(type) {
|
|
37924
|
+
return type === "assistant" || type === "stream_event" || type === "user";
|
|
37925
|
+
}
|
|
37923
37926
|
function findUserInstalledClaude(binName) {
|
|
37924
37927
|
const home = homedir3();
|
|
37925
37928
|
const abs = [
|
|
@@ -39980,50 +39983,72 @@ ${full.slice(-8e3)}`;
|
|
|
39980
39983
|
let cappedOut = false;
|
|
39981
39984
|
let narrated = false;
|
|
39982
39985
|
const turn = live.turnSeq;
|
|
39983
|
-
|
|
39984
|
-
|
|
39985
|
-
|
|
39986
|
-
|
|
39987
|
-
|
|
39988
|
-
|
|
39989
|
-
|
|
39990
|
-
|
|
39991
|
-
|
|
39992
|
-
|
|
39993
|
-
|
|
39994
|
-
|
|
39995
|
-
|
|
39996
|
-
|
|
39997
|
-
|
|
39998
|
-
|
|
39999
|
-
|
|
40000
|
-
|
|
40001
|
-
|
|
40002
|
-
|
|
40003
|
-
|
|
40004
|
-
|
|
40005
|
-
|
|
40006
|
-
|
|
40007
|
-
|
|
40008
|
-
|
|
40009
|
-
|
|
40010
|
-
|
|
40011
|
-
|
|
40012
|
-
|
|
40013
|
-
|
|
39986
|
+
live.gradePending = true;
|
|
39987
|
+
try {
|
|
39988
|
+
for (; ; ) {
|
|
39989
|
+
if (live.rv !== rv) {
|
|
39990
|
+
log(`[work] quiescence wait for ${live.sessionId} dropped \u2014 another run owns the session`);
|
|
39991
|
+
this.clearWorkNarration(live, narrated);
|
|
39992
|
+
return;
|
|
39993
|
+
}
|
|
39994
|
+
if (live.gone) {
|
|
39995
|
+
log(`[work] quiescence wait for ${live.sessionId} dropped \u2014 the session was torn down`);
|
|
39996
|
+
this.clearWorkNarration(live, narrated);
|
|
39997
|
+
return;
|
|
39998
|
+
}
|
|
39999
|
+
if (live.turnSeq !== turn) {
|
|
40000
|
+
log(`[work] quiescence wait for ${live.sessionId} superseded by a new turn`);
|
|
40001
|
+
this.clearWorkNarration(live, narrated);
|
|
40002
|
+
return;
|
|
40003
|
+
}
|
|
40004
|
+
const v = live.ledger.verdict(Date.now());
|
|
40005
|
+
if (v.quiescent)
|
|
40006
|
+
break;
|
|
40007
|
+
if (Date.now() - started2 >= QUIESCENCE_MAX_MS) {
|
|
40008
|
+
cappedOut = true;
|
|
40009
|
+
break;
|
|
40010
|
+
}
|
|
40011
|
+
if (!narrated && live.sessionId) {
|
|
40012
|
+
narrated = true;
|
|
40013
|
+
this.send({
|
|
40014
|
+
type: "agent:narration",
|
|
40015
|
+
sessionId: live.sessionId,
|
|
40016
|
+
text: `Waiting for ${v.waiting.length} background ${v.waiting.length === 1 ? "task" : "tasks"} to finish\u2026`,
|
|
40017
|
+
engineLabel: "Claude Code"
|
|
40018
|
+
}, live.origin);
|
|
40019
|
+
}
|
|
40020
|
+
await new Promise((res) => setTimeout(res, QUIESCENCE_POLL_MS));
|
|
40014
40021
|
}
|
|
40015
|
-
|
|
40022
|
+
this.clearWorkNarration(live, narrated);
|
|
40023
|
+
live.ledger.sweep(Date.now());
|
|
40024
|
+
const outstanding = live.ledger.summarize(Date.now());
|
|
40025
|
+
if (cappedOut)
|
|
40026
|
+
log(`[work] quiescence cap reached for ${live.sessionId}; grading anyway with: ${outstanding.join("; ") || "(nothing outstanding)"}`);
|
|
40027
|
+
else if (Date.now() - started2 > 1e3)
|
|
40028
|
+
log(`[work] ${live.sessionId} settled after ${Math.round((Date.now() - started2) / 1e3)}s \u2014 grading now`);
|
|
40029
|
+
if (!cappedOut && outstanding.length)
|
|
40030
|
+
log(`[work] grading with work still in flight: ${outstanding.join("; ")}`);
|
|
40031
|
+
await this.runVerification(live, finalText, didWork);
|
|
40032
|
+
} finally {
|
|
40033
|
+
live.gradePending = false;
|
|
40034
|
+
}
|
|
40035
|
+
}
|
|
40036
|
+
/**
|
|
40037
|
+
* Mark a turn the engine started on its own as busy — exactly what a send does.
|
|
40038
|
+
*
|
|
40039
|
+
* Bumping `turnSeq` is deliberate: a quiescence wait for the PREVIOUS turn must see itself
|
|
40040
|
+
* superseded, the same way it would by a turn we started, rather than grade the old final
|
|
40041
|
+
* text while the new turn runs.
|
|
40042
|
+
*/
|
|
40043
|
+
adoptSelfStartedTurn(live) {
|
|
40044
|
+
log(`[turn] ${live.sessionId || "(pending)"} started a turn on its own \u2014 marking busy`);
|
|
40045
|
+
live.streaming = true;
|
|
40046
|
+
live.turnSeq++;
|
|
40047
|
+
live.lastActivity = Date.now();
|
|
40048
|
+
if (live.idleTimer) {
|
|
40049
|
+
clearTimeout(live.idleTimer);
|
|
40050
|
+
live.idleTimer = void 0;
|
|
40016
40051
|
}
|
|
40017
|
-
this.clearWorkNarration(live, narrated);
|
|
40018
|
-
live.ledger.sweep(Date.now());
|
|
40019
|
-
const outstanding = live.ledger.summarize(Date.now());
|
|
40020
|
-
if (cappedOut)
|
|
40021
|
-
log(`[work] quiescence cap reached for ${live.sessionId}; grading anyway with: ${outstanding.join("; ") || "(nothing outstanding)"}`);
|
|
40022
|
-
else if (Date.now() - started2 > 1e3)
|
|
40023
|
-
log(`[work] ${live.sessionId} settled after ${Math.round((Date.now() - started2) / 1e3)}s \u2014 grading now`);
|
|
40024
|
-
if (!cappedOut && outstanding.length)
|
|
40025
|
-
log(`[work] grading with work still in flight: ${outstanding.join("; ")}`);
|
|
40026
|
-
await this.runVerification(live, finalText, didWork);
|
|
40027
40052
|
}
|
|
40028
40053
|
/** Take down the "waiting on background work" strip, if we put one up. */
|
|
40029
40054
|
clearWorkNarration(live, narrated) {
|
|
@@ -42557,6 +42582,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
|
|
|
42557
42582
|
}
|
|
42558
42583
|
const sid = live.sessionId;
|
|
42559
42584
|
const parentToolUseId = message.parent_tool_use_id ?? void 0;
|
|
42585
|
+
if (!live.streaming && !live.reaped && isTurnBearingFrame(message.type))
|
|
42586
|
+
this.adoptSelfStartedTurn(live);
|
|
42560
42587
|
switch (message.type) {
|
|
42561
42588
|
case "stream_event": {
|
|
42562
42589
|
const event = message.event;
|
|
@@ -43314,6 +43341,7 @@ ${err2.stack}` : ""}` : String(err2);
|
|
|
43314
43341
|
emit2({ type: "agent:status", sessionId: sid, status: "error" });
|
|
43315
43342
|
}
|
|
43316
43343
|
} finally {
|
|
43344
|
+
live.gone = true;
|
|
43317
43345
|
if (live.idleTimer) {
|
|
43318
43346
|
clearTimeout(live.idleTimer);
|
|
43319
43347
|
live.idleTimer = void 0;
|
|
@@ -43522,6 +43550,7 @@ ${err2.stack}` : ""}` : String(err2);
|
|
|
43522
43550
|
live.abort.abort();
|
|
43523
43551
|
} catch {
|
|
43524
43552
|
}
|
|
43553
|
+
live.gone = true;
|
|
43525
43554
|
}
|
|
43526
43555
|
/** M7 — stop ONE background task (vs interruptSession which aborts the whole
|
|
43527
43556
|
* turn). Driver-only, same origin guard. No-op if the session/task is gone. */
|
|
@@ -44247,12 +44276,45 @@ ${lines.join("\n")}
|
|
|
44247
44276
|
/** Close an idle session's Query (→ child process + IPC freed via runConsumer's
|
|
44248
44277
|
* finally), keeping the on-disk session resumable. Deletes from the live map
|
|
44249
44278
|
* FIRST so a racing sendMessage misses it and cleanly re-creates with resume. */
|
|
44279
|
+
/**
|
|
44280
|
+
* Is this session, whatever `streaming` says, still in the middle of something?
|
|
44281
|
+
*
|
|
44282
|
+
* `streaming` only tracks turns WE started. A CLI running its own background monitor
|
|
44283
|
+
* starts turns by itself when events land, and between two of those — or during a long
|
|
44284
|
+
* tool call inside one — the session reads as idle here while the engine is hard at work.
|
|
44285
|
+
* The memory monitor's moderate-pressure reclaim reaped exactly such a session, 60 seconds
|
|
44286
|
+
* "idle" with a batch barrier that had just reported "1 still running": the CLI carried on
|
|
44287
|
+
* for another 69 minutes, un-mapped and ungradeable. Work the ledger is awaiting, a job
|
|
44288
|
+
* that is running, a wait inside `await_jobs`, or a turn-end grade still waiting for
|
|
44289
|
+
* quiescence — any of these means the session is busy.
|
|
44290
|
+
*/
|
|
44291
|
+
hasWorkInFlight(live) {
|
|
44292
|
+
if (live.gradePending)
|
|
44293
|
+
return true;
|
|
44294
|
+
if ((live.awaitDepth ?? 0) > 0)
|
|
44295
|
+
return true;
|
|
44296
|
+
try {
|
|
44297
|
+
if (live.ledger.verdict(Date.now()).waiting.length > 0)
|
|
44298
|
+
return true;
|
|
44299
|
+
} catch {
|
|
44300
|
+
}
|
|
44301
|
+
try {
|
|
44302
|
+
if (live.jobs?.list().some((j) => j.status === "running"))
|
|
44303
|
+
return true;
|
|
44304
|
+
} catch {
|
|
44305
|
+
}
|
|
44306
|
+
return false;
|
|
44307
|
+
}
|
|
44250
44308
|
reapIdleSession(sessionId, force = false) {
|
|
44251
44309
|
const live = this.liveSessions.get(sessionId);
|
|
44252
44310
|
if (!live || live.streaming || live.reaped)
|
|
44253
44311
|
return false;
|
|
44254
44312
|
if (this.isHeld(live) && !force)
|
|
44255
44313
|
return false;
|
|
44314
|
+
if (!force && this.hasWorkInFlight(live)) {
|
|
44315
|
+
log(`[reap] ${sessionId} looks idle but has work in flight \u2014 left alone`);
|
|
44316
|
+
return false;
|
|
44317
|
+
}
|
|
44256
44318
|
log("Reaping idle session:", sessionId);
|
|
44257
44319
|
live.reaped = true;
|
|
44258
44320
|
this.emitLifecycle("SessionEnd", { sessionId, reason: force ? "forced" : "idle-reap" });
|
|
@@ -44301,6 +44363,10 @@ ${lines.join("\n")}
|
|
|
44301
44363
|
let n = 0;
|
|
44302
44364
|
for (const live of [...this.liveSessions.values()]) {
|
|
44303
44365
|
if (!live.streaming && !live.reaped) {
|
|
44366
|
+
if (this.hasWorkInFlight(live)) {
|
|
44367
|
+
log(`[reap] critical reclaim spared ${live.sessionId}: work in flight`);
|
|
44368
|
+
continue;
|
|
44369
|
+
}
|
|
44304
44370
|
if (this.reapIdleSession(live.sessionId, true))
|
|
44305
44371
|
n++;
|
|
44306
44372
|
}
|
|
@@ -44325,6 +44391,7 @@ ${lines.join("\n")}
|
|
|
44325
44391
|
if (live.reaped)
|
|
44326
44392
|
continue;
|
|
44327
44393
|
live.reaped = true;
|
|
44394
|
+
live.gone = true;
|
|
44328
44395
|
if (live.idleTimer) {
|
|
44329
44396
|
clearTimeout(live.idleTimer);
|
|
44330
44397
|
live.idleTimer = void 0;
|
|
@@ -79502,7 +79569,7 @@ function alphabet(letters) {
|
|
|
79502
79569
|
};
|
|
79503
79570
|
}
|
|
79504
79571
|
// @__NO_SIDE_EFFECTS__
|
|
79505
|
-
function
|
|
79572
|
+
function join67(separator = "") {
|
|
79506
79573
|
astr("join", separator);
|
|
79507
79574
|
return {
|
|
79508
79575
|
encode: (from) => {
|
|
@@ -79707,7 +79774,7 @@ var init_esm = __esm({
|
|
|
79707
79774
|
convertRadix2,
|
|
79708
79775
|
radix,
|
|
79709
79776
|
radix2,
|
|
79710
|
-
join:
|
|
79777
|
+
join: join67,
|
|
79711
79778
|
padding
|
|
79712
79779
|
};
|
|
79713
79780
|
}
|
|
@@ -81254,7 +81321,7 @@ var mesh_ca_exports = {};
|
|
|
81254
81321
|
__export(mesh_ca_exports, {
|
|
81255
81322
|
netCaCommand: () => netCaCommand
|
|
81256
81323
|
});
|
|
81257
|
-
import { chmodSync as chmodSync8, existsSync as
|
|
81324
|
+
import { chmodSync as chmodSync8, existsSync as existsSync49, mkdirSync as mkdirSync45, readFileSync as readFileSync54, writeFileSync as writeFileSync46 } from "node:fs";
|
|
81258
81325
|
import { join as join87, resolve as resolve13 } from "node:path";
|
|
81259
81326
|
import { createInterface as createInterface2 } from "node:readline";
|
|
81260
81327
|
function die(msg) {
|
|
@@ -81302,12 +81369,12 @@ function ensureDir(p) {
|
|
|
81302
81369
|
async function openCa(dir2) {
|
|
81303
81370
|
const gPath = join87(dir2, "genesis.bin");
|
|
81304
81371
|
const sPath = join87(dir2, "ca.sealed");
|
|
81305
|
-
if (!
|
|
81372
|
+
if (!existsSync49(gPath) || !existsSync49(sPath)) {
|
|
81306
81373
|
die(`No mesh CA in ${dir2}. Run: tesseract-agent net init --org NAME --ca-dir ${dir2}`);
|
|
81307
81374
|
}
|
|
81308
|
-
const genesisBytes = new Uint8Array(
|
|
81375
|
+
const genesisBytes = new Uint8Array(readFileSync54(gPath));
|
|
81309
81376
|
const genesis = decodeGenesis(genesisBytes);
|
|
81310
|
-
const sealed = decodeRecoveryBundle(new Uint8Array(
|
|
81377
|
+
const sealed = decodeRecoveryBundle(new Uint8Array(readFileSync54(sPath)));
|
|
81311
81378
|
const pass = await readPassphrase("CA passphrase: ");
|
|
81312
81379
|
let seed;
|
|
81313
81380
|
try {
|
|
@@ -81323,7 +81390,7 @@ async function netCaCommand(rest, flags) {
|
|
|
81323
81390
|
if (sub === "init") {
|
|
81324
81391
|
const org = typeof flags.org === "string" ? flags.org.trim() : "";
|
|
81325
81392
|
if (!org) die("Usage: tesseract-agent net init --org NAME [--ca-dir DIR]");
|
|
81326
|
-
if (
|
|
81393
|
+
if (existsSync49(join87(caDir, "ca.sealed"))) {
|
|
81327
81394
|
die(`A mesh CA already exists in ${caDir}. Refusing to overwrite it.`);
|
|
81328
81395
|
}
|
|
81329
81396
|
const pass = await readPassphrase("New CA passphrase: ");
|
|
@@ -81481,7 +81548,7 @@ var init_mesh_ca = __esm({
|
|
|
81481
81548
|
|
|
81482
81549
|
// src/cli.ts
|
|
81483
81550
|
init_base_paths();
|
|
81484
|
-
import { existsSync as
|
|
81551
|
+
import { existsSync as existsSync50, mkdtempSync as mkdtempSync4, readFileSync as readFileSync56, rmSync as rmSync13 } from "node:fs";
|
|
81485
81552
|
import { createHash as createHash9 } from "node:crypto";
|
|
81486
81553
|
import { execFileSync as execFileSync6, spawn as spawn14 } from "node:child_process";
|
|
81487
81554
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
@@ -109557,7 +109624,7 @@ async function startLocalServer(opts) {
|
|
|
109557
109624
|
|
|
109558
109625
|
// ../../packages/host-core/dist/daemon-runtime.js
|
|
109559
109626
|
init_base_paths();
|
|
109560
|
-
import { readFileSync as readFileSync49, writeFileSync as writeFileSync40, existsSync as
|
|
109627
|
+
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
109628
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
109562
109629
|
import { join as join77 } from "node:path";
|
|
109563
109630
|
import { randomBytes as randomBytes10 } from "node:crypto";
|
|
@@ -109819,6 +109886,7 @@ async function getPeerIdentityPub(opts) {
|
|
|
109819
109886
|
// ../../packages/host-core/dist/mesh/node.js
|
|
109820
109887
|
import { createSocket as createSocket2 } from "node:dgram";
|
|
109821
109888
|
import { createRequire as createRequire4 } from "node:module";
|
|
109889
|
+
init_credentials();
|
|
109822
109890
|
|
|
109823
109891
|
// ../../packages/host-core/dist/mesh/bundle-gossip.js
|
|
109824
109892
|
var BundleOfferLedger = class {
|
|
@@ -109850,15 +109918,429 @@ var BundleOfferLedger = class {
|
|
|
109850
109918
|
}
|
|
109851
109919
|
};
|
|
109852
109920
|
|
|
109921
|
+
// ../../packages/host-core/dist/mesh/netd-engine.js
|
|
109922
|
+
init_dist6();
|
|
109923
|
+
|
|
109924
|
+
// ../../packages/host-core/dist/mesh/netd-client.js
|
|
109925
|
+
import { connect as connect2 } from "node:net";
|
|
109926
|
+
import { platform as platform3 } from "node:process";
|
|
109927
|
+
var NETD_WIRE_VERSION = 2;
|
|
109928
|
+
var MAX_LINE = 1024 * 1024;
|
|
109929
|
+
var TIMEOUT_MS3 = 15e3;
|
|
109930
|
+
function netdEndpoint() {
|
|
109931
|
+
if (platform3 === "win32")
|
|
109932
|
+
return "\\\\.\\pipe\\tesseract-netd";
|
|
109933
|
+
if (platform3 === "darwin")
|
|
109934
|
+
return "/var/run/tesseract-netd.sock";
|
|
109935
|
+
return "/run/tesseract-netd.sock";
|
|
109936
|
+
}
|
|
109937
|
+
function endpointOverride() {
|
|
109938
|
+
return process.env.CCB_NETD_SOCKET ?? null;
|
|
109939
|
+
}
|
|
109940
|
+
function fail2(code, detail) {
|
|
109941
|
+
return { ok: false, code, detail };
|
|
109942
|
+
}
|
|
109943
|
+
async function call(line) {
|
|
109944
|
+
const endpoint2 = endpointOverride() ?? netdEndpoint();
|
|
109945
|
+
return new Promise((resolve16) => {
|
|
109946
|
+
let settled = false;
|
|
109947
|
+
const done = (r) => {
|
|
109948
|
+
if (settled)
|
|
109949
|
+
return;
|
|
109950
|
+
settled = true;
|
|
109951
|
+
try {
|
|
109952
|
+
sock.destroy();
|
|
109953
|
+
} catch {
|
|
109954
|
+
}
|
|
109955
|
+
resolve16(r);
|
|
109956
|
+
};
|
|
109957
|
+
let sock;
|
|
109958
|
+
try {
|
|
109959
|
+
sock = connect2(endpoint2);
|
|
109960
|
+
} catch (e) {
|
|
109961
|
+
return resolve16(fail2("not-installed", e instanceof Error ? e.message : String(e)));
|
|
109962
|
+
}
|
|
109963
|
+
const timer2 = setTimeout(() => {
|
|
109964
|
+
done(fail2("timeout", `no answer from the network helper in ${TIMEOUT_MS3}ms`));
|
|
109965
|
+
}, TIMEOUT_MS3);
|
|
109966
|
+
timer2.unref?.();
|
|
109967
|
+
sock.setTimeout(TIMEOUT_MS3);
|
|
109968
|
+
sock.on("timeout", () => {
|
|
109969
|
+
clearTimeout(timer2);
|
|
109970
|
+
done(fail2("timeout", "socket idle"));
|
|
109971
|
+
});
|
|
109972
|
+
sock.on("error", (e) => {
|
|
109973
|
+
clearTimeout(timer2);
|
|
109974
|
+
const absent = e.code === "ENOENT" || e.code === "ECONNREFUSED";
|
|
109975
|
+
done(fail2(absent ? "not-installed" : "io", e.message));
|
|
109976
|
+
});
|
|
109977
|
+
let buf = "";
|
|
109978
|
+
sock.on("data", (chunk) => {
|
|
109979
|
+
buf += chunk.toString("utf8");
|
|
109980
|
+
if (buf.length > MAX_LINE) {
|
|
109981
|
+
clearTimeout(timer2);
|
|
109982
|
+
done(fail2("protocol", "the helper sent an oversized line"));
|
|
109983
|
+
return;
|
|
109984
|
+
}
|
|
109985
|
+
const nl = buf.indexOf("\n");
|
|
109986
|
+
if (nl === -1)
|
|
109987
|
+
return;
|
|
109988
|
+
clearTimeout(timer2);
|
|
109989
|
+
done({ ok: true, line: buf.slice(0, nl) });
|
|
109990
|
+
});
|
|
109991
|
+
sock.on("close", () => {
|
|
109992
|
+
clearTimeout(timer2);
|
|
109993
|
+
done(fail2("protocol", "the helper closed the connection without answering"));
|
|
109994
|
+
});
|
|
109995
|
+
sock.on("connect", () => {
|
|
109996
|
+
sock.write(`${line}
|
|
109997
|
+
`);
|
|
109998
|
+
});
|
|
109999
|
+
});
|
|
110000
|
+
}
|
|
110001
|
+
function parse3(line) {
|
|
110002
|
+
let body;
|
|
110003
|
+
try {
|
|
110004
|
+
body = JSON.parse(line);
|
|
110005
|
+
} catch {
|
|
110006
|
+
return fail2("protocol", "the helper sent something that is not JSON");
|
|
110007
|
+
}
|
|
110008
|
+
if (typeof body !== "object" || body === null) {
|
|
110009
|
+
return fail2("protocol", "the helper sent something that is not an object");
|
|
110010
|
+
}
|
|
110011
|
+
const o = body;
|
|
110012
|
+
if (o.ok === false) {
|
|
110013
|
+
const code = typeof o.code === "string" ? o.code : "refused";
|
|
110014
|
+
const detail = typeof o.detail === "string" ? o.detail : "the helper refused";
|
|
110015
|
+
return fail2(code, detail);
|
|
110016
|
+
}
|
|
110017
|
+
if (o.ok !== true)
|
|
110018
|
+
return fail2("protocol", "the helper did not say whether it succeeded");
|
|
110019
|
+
return { ok: true, body: o };
|
|
110020
|
+
}
|
|
110021
|
+
async function request(line) {
|
|
110022
|
+
const r = await call(line);
|
|
110023
|
+
return r.ok ? parse3(r.line) : r;
|
|
110024
|
+
}
|
|
110025
|
+
function hex4(b) {
|
|
110026
|
+
return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
110027
|
+
}
|
|
110028
|
+
async function netdHello() {
|
|
110029
|
+
const r = await request(JSON.stringify({ op: "hello", wireVersion: NETD_WIRE_VERSION }));
|
|
110030
|
+
if (!r.ok)
|
|
110031
|
+
return r;
|
|
110032
|
+
const v = r.body.wireVersion;
|
|
110033
|
+
if (typeof v !== "number")
|
|
110034
|
+
return fail2("protocol", "the helper did not report a wire version");
|
|
110035
|
+
if (v !== NETD_WIRE_VERSION) {
|
|
110036
|
+
return fail2("wire-version", `the helper speaks ${v}, this build speaks ${NETD_WIRE_VERSION}`);
|
|
110037
|
+
}
|
|
110038
|
+
return { ok: true, wireVersion: v };
|
|
110039
|
+
}
|
|
110040
|
+
async function netdStatus() {
|
|
110041
|
+
const r = await request(JSON.stringify({ op: "status" }));
|
|
110042
|
+
if (!r.ok)
|
|
110043
|
+
return r;
|
|
110044
|
+
const meshes = Array.isArray(r.body.meshes) ? r.body.meshes.filter((m) => typeof m === "string") : [];
|
|
110045
|
+
const iface = typeof r.body.interface === "string" ? r.body.interface : null;
|
|
110046
|
+
return { ok: true, meshes, interface: iface };
|
|
110047
|
+
}
|
|
110048
|
+
async function netdUp(args) {
|
|
110049
|
+
const r = await request(JSON.stringify({
|
|
110050
|
+
op: "up",
|
|
110051
|
+
meshId: args.meshId,
|
|
110052
|
+
genesis: hex4(args.genesis),
|
|
110053
|
+
cert: hex4(args.cert),
|
|
110054
|
+
fullTunnel: args.fullTunnel === true,
|
|
110055
|
+
...args.staticPrivate ? { staticPrivate: hex4(args.staticPrivate) } : {},
|
|
110056
|
+
...args.bundle ? { bundle: hex4(args.bundle) } : {}
|
|
110057
|
+
}));
|
|
110058
|
+
return r.ok ? { ok: true } : r;
|
|
110059
|
+
}
|
|
110060
|
+
async function netdHint(args) {
|
|
110061
|
+
const r = await request(JSON.stringify({
|
|
110062
|
+
op: "hint",
|
|
110063
|
+
meshId: args.meshId,
|
|
110064
|
+
staticPub: hex4(args.staticPub),
|
|
110065
|
+
endpoints: args.endpoints,
|
|
110066
|
+
relayed: args.relayed === true
|
|
110067
|
+
}));
|
|
110068
|
+
return r.ok ? { ok: true } : r;
|
|
110069
|
+
}
|
|
110070
|
+
async function netdBundle(meshId, bundle) {
|
|
110071
|
+
const r = await request(JSON.stringify({ op: "bundle", meshId, bundle: hex4(bundle) }));
|
|
110072
|
+
return r.ok ? { ok: true } : r;
|
|
110073
|
+
}
|
|
110074
|
+
async function netdSetExitNode(meshId, staticPub) {
|
|
110075
|
+
const r = await request(JSON.stringify({
|
|
110076
|
+
op: "setExitNode",
|
|
110077
|
+
meshId,
|
|
110078
|
+
staticPub: staticPub ? hex4(staticPub) : null
|
|
110079
|
+
}));
|
|
110080
|
+
return r.ok ? { ok: true } : r;
|
|
110081
|
+
}
|
|
110082
|
+
async function netdNodeStatus(meshId) {
|
|
110083
|
+
const r = await request(JSON.stringify({ op: "nodeStatus", meshId }));
|
|
110084
|
+
if (!r.ok)
|
|
110085
|
+
return r;
|
|
110086
|
+
const b = r.body;
|
|
110087
|
+
const num2 = (k) => typeof b[k] === "number" ? b[k] : 0;
|
|
110088
|
+
const strs = (k) => Array.isArray(b[k]) ? b[k].filter((x) => typeof x === "string") : [];
|
|
110089
|
+
if (b.node !== true)
|
|
110090
|
+
return fail2("protocol", "the helper did not answer with a node status");
|
|
110091
|
+
const pubHex = typeof b.localStaticPub === "string" ? b.localStaticPub : "";
|
|
110092
|
+
return {
|
|
110093
|
+
ok: true,
|
|
110094
|
+
node: {
|
|
110095
|
+
running: b.running === true,
|
|
110096
|
+
port: num2("port"),
|
|
110097
|
+
peers: num2("peers"),
|
|
110098
|
+
established: strs("established"),
|
|
110099
|
+
relayed: strs("relayed"),
|
|
110100
|
+
policyEpoch: num2("policyEpoch"),
|
|
110101
|
+
revoked: b.revoked === true,
|
|
110102
|
+
lastError: typeof b.lastError === "string" ? b.lastError : null,
|
|
110103
|
+
localStaticPub: Uint8Array.from(Buffer.from(pubHex, "hex")),
|
|
110104
|
+
meter: {
|
|
110105
|
+
txDirectBytes: num2("txDirectBytes"),
|
|
110106
|
+
txDirectPackets: num2("txDirectPackets"),
|
|
110107
|
+
txRelayedBytes: num2("txRelayedBytes"),
|
|
110108
|
+
txRelayedPackets: num2("txRelayedPackets"),
|
|
110109
|
+
rxDirectBytes: num2("rxDirectBytes"),
|
|
110110
|
+
rxDirectPackets: num2("rxDirectPackets"),
|
|
110111
|
+
rxRelayedBytes: num2("rxRelayedBytes"),
|
|
110112
|
+
rxRelayedPackets: num2("rxRelayedPackets"),
|
|
110113
|
+
forwardedBytes: num2("forwardedBytes"),
|
|
110114
|
+
forwardedPackets: num2("forwardedPackets")
|
|
110115
|
+
}
|
|
110116
|
+
}
|
|
110117
|
+
};
|
|
110118
|
+
}
|
|
110119
|
+
async function netdDown(meshId) {
|
|
110120
|
+
const r = await request(JSON.stringify({ op: "down", meshId }));
|
|
110121
|
+
return r.ok ? { ok: true } : r;
|
|
110122
|
+
}
|
|
110123
|
+
async function netdAvailable() {
|
|
110124
|
+
return (await netdHello()).ok;
|
|
110125
|
+
}
|
|
110126
|
+
|
|
110127
|
+
// ../../packages/host-core/dist/mesh/netd-engine.js
|
|
110128
|
+
var NETD_POLL_MS = 1e3;
|
|
110129
|
+
var NetdEngine = class {
|
|
110130
|
+
#meshDir;
|
|
110131
|
+
#meshId;
|
|
110132
|
+
#localStaticPub;
|
|
110133
|
+
#hooks;
|
|
110134
|
+
#snapshot = null;
|
|
110135
|
+
#pendingEndpoints = /* @__PURE__ */ new Map();
|
|
110136
|
+
#events = [];
|
|
110137
|
+
#seenEstablished = /* @__PURE__ */ new Set();
|
|
110138
|
+
#seenRelayed = /* @__PURE__ */ new Set();
|
|
110139
|
+
#timer = null;
|
|
110140
|
+
#announced = false;
|
|
110141
|
+
#lastError = null;
|
|
110142
|
+
#stopped = false;
|
|
110143
|
+
constructor(meshDir2, cert, hooks2) {
|
|
110144
|
+
this.#meshDir = meshDir2;
|
|
110145
|
+
this.#hooks = hooks2;
|
|
110146
|
+
const d = decodeCert(cert).details;
|
|
110147
|
+
this.#meshId = hex3(d.genesisFp);
|
|
110148
|
+
this.#localStaticPub = Buffer.from(d.staticPub);
|
|
110149
|
+
this.#timer = setInterval(() => void this.#poll(), NETD_POLL_MS);
|
|
110150
|
+
this.#timer.unref?.();
|
|
110151
|
+
void this.#poll();
|
|
110152
|
+
}
|
|
110153
|
+
/** Read netd's view now rather than waiting for the timer. Exposed for tests and for
|
|
110154
|
+
* the moment right after `up` so status does not lag a full interval. */
|
|
110155
|
+
async refresh() {
|
|
110156
|
+
await this.#poll();
|
|
110157
|
+
}
|
|
110158
|
+
async #poll() {
|
|
110159
|
+
if (this.#stopped)
|
|
110160
|
+
return;
|
|
110161
|
+
const r = await netdNodeStatus(this.#meshDir);
|
|
110162
|
+
if (!r.ok) {
|
|
110163
|
+
if (r.code !== "not-running" && r.code !== "not-installed") {
|
|
110164
|
+
this.#lastError = `netd: ${r.detail}`;
|
|
110165
|
+
}
|
|
110166
|
+
return;
|
|
110167
|
+
}
|
|
110168
|
+
const s = r.node;
|
|
110169
|
+
const prev = this.#snapshot;
|
|
110170
|
+
this.#snapshot = s;
|
|
110171
|
+
if (s.lastError)
|
|
110172
|
+
this.#lastError = s.lastError;
|
|
110173
|
+
for (const k of s.established) {
|
|
110174
|
+
if (!this.#seenEstablished.has(k)) {
|
|
110175
|
+
this.#seenEstablished.add(k);
|
|
110176
|
+
this.#events.push({ kind: "peerEstablished", staticPub: Buffer.from(k, "hex") });
|
|
110177
|
+
}
|
|
110178
|
+
}
|
|
110179
|
+
const relayedNow = new Set(s.relayed);
|
|
110180
|
+
for (const k of relayedNow) {
|
|
110181
|
+
if (!this.#seenRelayed.has(k)) {
|
|
110182
|
+
this.#seenRelayed.add(k);
|
|
110183
|
+
this.#events.push({ kind: "pathChanged", staticPub: Buffer.from(k, "hex"), detail: "relay" });
|
|
110184
|
+
}
|
|
110185
|
+
}
|
|
110186
|
+
for (const k of [...this.#seenRelayed]) {
|
|
110187
|
+
if (!relayedNow.has(k)) {
|
|
110188
|
+
this.#seenRelayed.delete(k);
|
|
110189
|
+
this.#events.push({ kind: "pathChanged", staticPub: Buffer.from(k, "hex"), detail: "direct" });
|
|
110190
|
+
}
|
|
110191
|
+
}
|
|
110192
|
+
if (s.running && s.port > 0 && !this.#announced) {
|
|
110193
|
+
this.#announced = true;
|
|
110194
|
+
this.#hooks.log?.(`mesh: node running in the network helper on UDP port ${s.port}`);
|
|
110195
|
+
this.#hooks.onUp(s.port);
|
|
110196
|
+
}
|
|
110197
|
+
void prev;
|
|
110198
|
+
}
|
|
110199
|
+
// ── MeshEngineNative ────────────────────────────────────────────────────────────
|
|
110200
|
+
setBundle(b, _nowMs) {
|
|
110201
|
+
void netdBundle(this.#meshDir, b).then((r) => {
|
|
110202
|
+
if (!r.ok)
|
|
110203
|
+
this.#lastError = `bundle: ${r.detail}`;
|
|
110204
|
+
});
|
|
110205
|
+
}
|
|
110206
|
+
addPeer(staticPub, _overlayV4, _overlayV6) {
|
|
110207
|
+
const k = staticPub.toString("hex");
|
|
110208
|
+
if (!this.#pendingEndpoints.has(k))
|
|
110209
|
+
this.#pendingEndpoints.set(k, { endpoints: [], relayed: false });
|
|
110210
|
+
}
|
|
110211
|
+
addPath(staticPub, endpoint2, relayed) {
|
|
110212
|
+
const k = staticPub.toString("hex");
|
|
110213
|
+
const p = this.#pendingEndpoints.get(k) ?? { endpoints: [], relayed: false };
|
|
110214
|
+
if (!p.endpoints.includes(endpoint2))
|
|
110215
|
+
p.endpoints.push(endpoint2);
|
|
110216
|
+
p.relayed = p.relayed || relayed;
|
|
110217
|
+
this.#pendingEndpoints.set(k, p);
|
|
110218
|
+
}
|
|
110219
|
+
#flushHint(staticPub) {
|
|
110220
|
+
const k = staticPub.toString("hex");
|
|
110221
|
+
const p = this.#pendingEndpoints.get(k) ?? { endpoints: [], relayed: false };
|
|
110222
|
+
this.#pendingEndpoints.delete(k);
|
|
110223
|
+
void netdHint({ meshId: this.#meshDir, staticPub, endpoints: p.endpoints, relayed: p.relayed }).then((r) => {
|
|
110224
|
+
if (!r.ok)
|
|
110225
|
+
this.#lastError = `hint: ${r.detail}`;
|
|
110226
|
+
});
|
|
110227
|
+
}
|
|
110228
|
+
startHandshake(staticPub, _nowMs) {
|
|
110229
|
+
this.#flushHint(staticPub);
|
|
110230
|
+
}
|
|
110231
|
+
ensureHandshake(staticPub, _nowMs) {
|
|
110232
|
+
this.#flushHint(staticPub);
|
|
110233
|
+
}
|
|
110234
|
+
/** No UDP here — netd owns the socket. Never called in practice; kept for the interface. */
|
|
110235
|
+
injectUdp(_pkt, _from, _nowMs) {
|
|
110236
|
+
}
|
|
110237
|
+
tick(_nowMs) {
|
|
110238
|
+
}
|
|
110239
|
+
pollSend() {
|
|
110240
|
+
return null;
|
|
110241
|
+
}
|
|
110242
|
+
pollEvent() {
|
|
110243
|
+
return this.#events.shift() ?? null;
|
|
110244
|
+
}
|
|
110245
|
+
meter() {
|
|
110246
|
+
const m = this.#snapshot?.meter;
|
|
110247
|
+
const tx = (m?.txDirectBytes ?? 0) + (m?.txRelayedBytes ?? 0);
|
|
110248
|
+
return {
|
|
110249
|
+
txDirectBytes: m?.txDirectBytes ?? 0,
|
|
110250
|
+
txRelayedBytes: m?.txRelayedBytes ?? 0,
|
|
110251
|
+
rxDirectBytes: m?.rxDirectBytes ?? 0,
|
|
110252
|
+
rxRelayedBytes: m?.rxRelayedBytes ?? 0,
|
|
110253
|
+
forwardedBytes: m?.forwardedBytes ?? 0,
|
|
110254
|
+
forwardedPackets: m?.forwardedPackets ?? 0,
|
|
110255
|
+
relayedTxFraction: tx === 0 ? 0 : (m?.txRelayedBytes ?? 0) / tx
|
|
110256
|
+
};
|
|
110257
|
+
}
|
|
110258
|
+
localStaticPub() {
|
|
110259
|
+
return this.#localStaticPub;
|
|
110260
|
+
}
|
|
110261
|
+
meshId() {
|
|
110262
|
+
return this.#meshId;
|
|
110263
|
+
}
|
|
110264
|
+
policyEpoch() {
|
|
110265
|
+
return this.#snapshot?.policyEpoch ?? 0;
|
|
110266
|
+
}
|
|
110267
|
+
selfRevoked() {
|
|
110268
|
+
return this.#snapshot?.revoked === true;
|
|
110269
|
+
}
|
|
110270
|
+
peerCount() {
|
|
110271
|
+
return this.#snapshot?.peers ?? 0;
|
|
110272
|
+
}
|
|
110273
|
+
setExitNode(staticPub) {
|
|
110274
|
+
void netdSetExitNode(this.#meshDir, staticPub).then((r) => {
|
|
110275
|
+
if (!r.ok)
|
|
110276
|
+
this.#lastError = `exit node: ${r.detail}`;
|
|
110277
|
+
});
|
|
110278
|
+
}
|
|
110279
|
+
/** Is netd running the node right now, and on which port? */
|
|
110280
|
+
get running() {
|
|
110281
|
+
return this.#snapshot?.running === true;
|
|
110282
|
+
}
|
|
110283
|
+
get port() {
|
|
110284
|
+
return this.#snapshot && this.#snapshot.port > 0 ? this.#snapshot.port : null;
|
|
110285
|
+
}
|
|
110286
|
+
get lastError() {
|
|
110287
|
+
return this.#lastError;
|
|
110288
|
+
}
|
|
110289
|
+
stop() {
|
|
110290
|
+
this.#stopped = true;
|
|
110291
|
+
if (this.#timer) {
|
|
110292
|
+
clearInterval(this.#timer);
|
|
110293
|
+
this.#timer = null;
|
|
110294
|
+
}
|
|
110295
|
+
}
|
|
110296
|
+
};
|
|
110297
|
+
|
|
110298
|
+
// ../../packages/host-core/dist/mesh/node.js
|
|
110299
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
110300
|
+
|
|
110301
|
+
// ../../packages/host-core/dist/mesh/bundle-refresh.js
|
|
110302
|
+
init_dist6();
|
|
110303
|
+
var CONTEXT = "tsr-bundle-fetch-v1";
|
|
110304
|
+
var REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
110305
|
+
async function fetchBundle(args) {
|
|
110306
|
+
const none = { bundle: null, epoch: null };
|
|
110307
|
+
try {
|
|
110308
|
+
const ts = Date.now();
|
|
110309
|
+
const { privateKey } = await signingKeyFromSeed(args.sigPrivate);
|
|
110310
|
+
const message = new TextEncoder().encode(`${CONTEXT}
|
|
110311
|
+
${args.genesisFp.toLowerCase()}
|
|
110312
|
+
${args.staticPub.toLowerCase()}
|
|
110313
|
+
${ts}`);
|
|
110314
|
+
const sig = await sign2(privateKey, message);
|
|
110315
|
+
const doFetch = args.fetchImpl ?? fetch;
|
|
110316
|
+
const res = await doFetch(`${args.origin.replace(/\/$/, "")}/api/core/tesseract/mesh/meshes/by-genesis/${encodeURIComponent(args.genesisFp.toLowerCase())}/bundle`, {
|
|
110317
|
+
method: "GET",
|
|
110318
|
+
headers: {
|
|
110319
|
+
"x-tsr-node": args.staticPub.toLowerCase(),
|
|
110320
|
+
"x-tsr-ts": String(ts),
|
|
110321
|
+
"x-tsr-sig": Buffer.from(sig).toString("base64")
|
|
110322
|
+
}
|
|
110323
|
+
});
|
|
110324
|
+
if (!res.ok)
|
|
110325
|
+
return none;
|
|
110326
|
+
const body = await res.json();
|
|
110327
|
+
if (!body.bundle)
|
|
110328
|
+
return none;
|
|
110329
|
+
return { bundle: Uint8Array.from(Buffer.from(body.bundle, "hex")), epoch: body.epoch ?? null };
|
|
110330
|
+
} catch {
|
|
110331
|
+
return none;
|
|
110332
|
+
}
|
|
110333
|
+
}
|
|
110334
|
+
|
|
109853
110335
|
// ../../packages/host-core/dist/mesh/config.js
|
|
109854
110336
|
init_credentials();
|
|
109855
110337
|
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
|
|
110338
|
+
import { dirname as dirname31, join as join68 } from "node:path";
|
|
109857
110339
|
function meshDir() {
|
|
109858
|
-
return
|
|
110340
|
+
return join68(daemonDir2(), "mesh");
|
|
109859
110341
|
}
|
|
109860
110342
|
function meshesDir() {
|
|
109861
|
-
return
|
|
110343
|
+
return join68(meshDir(), "meshes");
|
|
109862
110344
|
}
|
|
109863
110345
|
var MESH_DIR_NAME_BYTES = 8;
|
|
109864
110346
|
function meshDirName(genesisFp) {
|
|
@@ -109876,7 +110358,7 @@ function oneMeshDir(meshId) {
|
|
|
109876
110358
|
if (!isMeshId(meshId)) {
|
|
109877
110359
|
throw new Error(`not a mesh id: ${JSON.stringify(meshId.slice(0, 64))}`);
|
|
109878
110360
|
}
|
|
109879
|
-
return
|
|
110361
|
+
return join68(meshesDir(), meshId);
|
|
109880
110362
|
}
|
|
109881
110363
|
var LEGACY_MESH_ID = "legacy";
|
|
109882
110364
|
var CERT_GENESIS_FP_OFFSET = 19;
|
|
@@ -109894,7 +110376,7 @@ var FILES = {
|
|
|
109894
110376
|
local: "local.json"
|
|
109895
110377
|
};
|
|
109896
110378
|
function readIfPresent(name, dir2 = meshDir()) {
|
|
109897
|
-
const p =
|
|
110379
|
+
const p = join68(dir2, name);
|
|
109898
110380
|
try {
|
|
109899
110381
|
return existsSync33(p) ? new Uint8Array(readFileSync47(p)) : void 0;
|
|
109900
110382
|
} catch {
|
|
@@ -109902,7 +110384,7 @@ function readIfPresent(name, dir2 = meshDir()) {
|
|
|
109902
110384
|
}
|
|
109903
110385
|
}
|
|
109904
110386
|
function migrateSingleMesh() {
|
|
109905
|
-
const legacyGenesis =
|
|
110387
|
+
const legacyGenesis = join68(meshDir(), FILES.genesis);
|
|
109906
110388
|
if (!existsSync33(legacyGenesis))
|
|
109907
110389
|
return null;
|
|
109908
110390
|
const id = meshIdFromCert(readIfPresent(FILES.cert)) ?? LEGACY_MESH_ID;
|
|
@@ -109911,11 +110393,11 @@ function migrateSingleMesh() {
|
|
|
109911
110393
|
mkdirSync36(dest, { recursive: true, mode: 448 });
|
|
109912
110394
|
chmodSync5(dest, 448);
|
|
109913
110395
|
for (const f of Object.values(FILES)) {
|
|
109914
|
-
const from =
|
|
110396
|
+
const from = join68(meshDir(), f);
|
|
109915
110397
|
if (existsSync33(from))
|
|
109916
|
-
renameSync11(from,
|
|
110398
|
+
renameSync11(from, join68(dest, f));
|
|
109917
110399
|
}
|
|
109918
|
-
const key2 =
|
|
110400
|
+
const key2 = join68(dest, FILES.key);
|
|
109919
110401
|
if (existsSync33(key2))
|
|
109920
110402
|
chmodSync5(key2, 384);
|
|
109921
110403
|
} catch {
|
|
@@ -109939,7 +110421,7 @@ function listMeshIds() {
|
|
|
109939
110421
|
}
|
|
109940
110422
|
function readLocal(meshId) {
|
|
109941
110423
|
try {
|
|
109942
|
-
return JSON.parse(readFileSync47(
|
|
110424
|
+
return JSON.parse(readFileSync47(join68(oneMeshDir(meshId), FILES.local), "utf8"));
|
|
109943
110425
|
} catch {
|
|
109944
110426
|
return null;
|
|
109945
110427
|
}
|
|
@@ -109947,7 +110429,7 @@ function readLocal(meshId) {
|
|
|
109947
110429
|
function writeLocal(meshId, state3) {
|
|
109948
110430
|
try {
|
|
109949
110431
|
mkdirSync36(oneMeshDir(meshId), { recursive: true, mode: 448 });
|
|
109950
|
-
writeFileSync35(
|
|
110432
|
+
writeFileSync35(join68(oneMeshDir(meshId), FILES.local), JSON.stringify(state3, null, 2), { mode: 384 });
|
|
109951
110433
|
} catch {
|
|
109952
110434
|
}
|
|
109953
110435
|
}
|
|
@@ -109980,7 +110462,7 @@ function loadMeshIdentity() {
|
|
|
109980
110462
|
return first === void 0 ? null : loadMesh(first);
|
|
109981
110463
|
}
|
|
109982
110464
|
function writeSecret(name, bytes2, dir2 = meshDir()) {
|
|
109983
|
-
const p =
|
|
110465
|
+
const p = join68(dir2, name);
|
|
109984
110466
|
writeFileSync35(p, bytes2, { mode: 384 });
|
|
109985
110467
|
try {
|
|
109986
110468
|
chmodSync5(p, 384);
|
|
@@ -109998,11 +110480,11 @@ function saveMeshIdentity(id) {
|
|
|
109998
110480
|
chmodSync5(meshDir(), 448);
|
|
109999
110481
|
} catch {
|
|
110000
110482
|
}
|
|
110001
|
-
writeFileSync35(
|
|
110002
|
-
writeFileSync35(
|
|
110483
|
+
writeFileSync35(join68(meshDir(), FILES.genesis), id.genesis);
|
|
110484
|
+
writeFileSync35(join68(meshDir(), FILES.cert), id.cert);
|
|
110003
110485
|
writeSecret(FILES.key, id.staticPrivate);
|
|
110004
110486
|
if (id.bundle)
|
|
110005
|
-
writeFileSync35(
|
|
110487
|
+
writeFileSync35(join68(meshDir(), FILES.bundle), id.bundle);
|
|
110006
110488
|
}
|
|
110007
110489
|
function saveMesh(meshId, id) {
|
|
110008
110490
|
const dir2 = oneMeshDir(meshId);
|
|
@@ -110019,13 +110501,13 @@ function saveMesh(meshId, id) {
|
|
|
110019
110501
|
chmodSync5(dir2, 448);
|
|
110020
110502
|
} catch {
|
|
110021
110503
|
}
|
|
110022
|
-
writeFileSync35(
|
|
110023
|
-
writeFileSync35(
|
|
110504
|
+
writeFileSync35(join68(dir2, FILES.genesis), id.genesis);
|
|
110505
|
+
writeFileSync35(join68(dir2, FILES.cert), id.cert);
|
|
110024
110506
|
writeSecret(FILES.key, id.staticPrivate, dir2);
|
|
110025
110507
|
if (id.sigPrivate)
|
|
110026
110508
|
writeSecret(FILES.sigKey, id.sigPrivate, dir2);
|
|
110027
110509
|
if (id.bundle)
|
|
110028
|
-
writeFileSync35(
|
|
110510
|
+
writeFileSync35(join68(dir2, FILES.bundle), id.bundle);
|
|
110029
110511
|
if (readLocal(meshId) === null)
|
|
110030
110512
|
writeLocal(meshId, { joinedAt: Date.now() });
|
|
110031
110513
|
}
|
|
@@ -110035,7 +110517,7 @@ function removeMesh(meshId) {
|
|
|
110035
110517
|
var STATUS_REFRESH_MS = 5e3;
|
|
110036
110518
|
var STATUS_STALE_MS = 2e4;
|
|
110037
110519
|
function statusPath(meshId) {
|
|
110038
|
-
return meshId === void 0 ?
|
|
110520
|
+
return meshId === void 0 ? join68(meshDir(), "status.json") : join68(oneMeshDir(meshId), "status.json");
|
|
110039
110521
|
}
|
|
110040
110522
|
function writeStatus(status2, meshId) {
|
|
110041
110523
|
try {
|
|
@@ -110066,7 +110548,7 @@ function cacheBundle(bundle, meshId) {
|
|
|
110066
110548
|
const id = meshId ?? listMeshIds()[0];
|
|
110067
110549
|
const dir2 = id === void 0 ? meshDir() : oneMeshDir(id);
|
|
110068
110550
|
mkdirSync36(dir2, { recursive: true, mode: 448 });
|
|
110069
|
-
writeFileSync35(
|
|
110551
|
+
writeFileSync35(join68(dir2, FILES.bundle), bundle);
|
|
110070
110552
|
} catch {
|
|
110071
110553
|
}
|
|
110072
110554
|
}
|
|
@@ -110222,6 +110704,9 @@ function loadMeshCore() {
|
|
|
110222
110704
|
}
|
|
110223
110705
|
var meshCore = loadMeshCore();
|
|
110224
110706
|
function meshEngineStatus() {
|
|
110707
|
+
if (process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint())) {
|
|
110708
|
+
return { available: true, reason: null };
|
|
110709
|
+
}
|
|
110225
110710
|
return { available: meshCore.available === true, reason: meshCore.loadError ?? null };
|
|
110226
110711
|
}
|
|
110227
110712
|
var TICK_MS2 = 1e3;
|
|
@@ -110317,6 +110802,8 @@ var MeshNode = class {
|
|
|
110317
110802
|
#engine = null;
|
|
110318
110803
|
#sock = null;
|
|
110319
110804
|
#timer = null;
|
|
110805
|
+
/** The policy refresh poll. See `bundle-refresh.ts` — this is what makes eviction real. */
|
|
110806
|
+
#refreshTimer = null;
|
|
110320
110807
|
#unsubscribe = null;
|
|
110321
110808
|
#identity = null;
|
|
110322
110809
|
/** The policy bundle we hold, as bytes, so we can OFFER it to a peer that is behind.
|
|
@@ -110389,8 +110876,11 @@ var MeshNode = class {
|
|
|
110389
110876
|
}
|
|
110390
110877
|
status() {
|
|
110391
110878
|
return {
|
|
110392
|
-
|
|
110393
|
-
|
|
110879
|
+
// In netd mode the engine is the helper's, and whether THIS process could load a
|
|
110880
|
+
// prebuilt is beside the point — a CLI install whose native fetch failed still has a
|
|
110881
|
+
// working network when the helper runs it, and must not say "engine unavailable".
|
|
110882
|
+
available: this.#engine instanceof NetdEngine ? true : meshCore.available,
|
|
110883
|
+
loadError: this.#engine instanceof NetdEngine ? null : meshCore.loadError,
|
|
110394
110884
|
enrolled: this.#identity !== null || this.#loadIdentity() !== null,
|
|
110395
110885
|
running: this.#engine !== null,
|
|
110396
110886
|
port: this.#port,
|
|
@@ -110407,7 +110897,22 @@ var MeshNode = class {
|
|
|
110407
110897
|
this.#established.has(hex6) ? this.#relayed.has(hex6) ? "relay" : "direct" : "none"
|
|
110408
110898
|
])),
|
|
110409
110899
|
meter: this.#engine?.meter() ?? null,
|
|
110410
|
-
|
|
110900
|
+
// THE POLICY EPOCH this node is actually running on.
|
|
110901
|
+
//
|
|
110902
|
+
// Read from the ENGINE, never from `bundle.bin`: the engine installs a bundle the
|
|
110903
|
+
// moment it verifies one, and a bundle pulled from a peer over the Noise session
|
|
110904
|
+
// never touches that file. Judging freshness by the file — which is what there was
|
|
110905
|
+
// to judge by — therefore reports a node as stale when it is current, and is how a
|
|
110906
|
+
// machine came to look a dozen epochs behind while carrying the right policy.
|
|
110907
|
+
//
|
|
110908
|
+
// It is the one number that answers "why is nothing passing": a node whose policy
|
|
110909
|
+
// predates a peer has no roster entry for it and drops every packet, correctly, with
|
|
110910
|
+
// nothing anywhere saying so.
|
|
110911
|
+
policyEpoch: this.#engine?.policyEpoch() ?? null,
|
|
110912
|
+
lastError: this.#lastError ?? (this.#engine instanceof NetdEngine ? this.#engine.lastError : null),
|
|
110913
|
+
// In netd mode "running" means netd runs it: an adapter with no node behind it yet
|
|
110914
|
+
// (routes not synced, helper just installed) is not a running node.
|
|
110915
|
+
...this.#engine instanceof NetdEngine && !this.#engine.running ? { running: false } : {},
|
|
110411
110916
|
// Surfaced so `net status` can say "removed" rather than "not running". Those look
|
|
110412
110917
|
// identical from outside and have completely different remedies.
|
|
110413
110918
|
removed: this.#revoked
|
|
@@ -110429,7 +110934,8 @@ var MeshNode = class {
|
|
|
110429
110934
|
reason: "this machine was removed from the network \u2014 ask an admin for a new invitation"
|
|
110430
110935
|
};
|
|
110431
110936
|
}
|
|
110432
|
-
|
|
110937
|
+
const inNetd = process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint());
|
|
110938
|
+
if (!inNetd && !meshCore.available) {
|
|
110433
110939
|
return { ok: false, reason: `mesh engine unavailable: ${meshCore.loadError ?? "no prebuilt"}` };
|
|
110434
110940
|
}
|
|
110435
110941
|
const id = this.#loadIdentity();
|
|
@@ -110439,20 +110945,46 @@ var MeshNode = class {
|
|
|
110439
110945
|
reason: this.#wantMeshId === null ? "this machine is not enrolled in a mesh" : `this machine is not enrolled in mesh ${this.#wantMeshId}`
|
|
110440
110946
|
};
|
|
110441
110947
|
}
|
|
110442
|
-
|
|
110443
|
-
|
|
110444
|
-
if (
|
|
110445
|
-
|
|
110446
|
-
|
|
110948
|
+
if (inNetd) {
|
|
110949
|
+
const meshDir2 = this.#wantMeshId ?? listMeshIds()[0] ?? null;
|
|
110950
|
+
if (!meshDir2)
|
|
110951
|
+
return { ok: false, reason: "this machine is not enrolled in a mesh" };
|
|
110952
|
+
try {
|
|
110953
|
+
this.#engine = new NetdEngine(meshDir2, id.cert, {
|
|
110954
|
+
// netd reports the node up: now this side has a port to advertise, and can
|
|
110955
|
+
// publish itself to the relay and the LAN. Before that there is nothing to say.
|
|
110956
|
+
onUp: (port) => {
|
|
110957
|
+
this.#port = port;
|
|
110958
|
+
this.#join();
|
|
110959
|
+
this.#startLan();
|
|
110960
|
+
this.#publishStatus();
|
|
110961
|
+
}
|
|
110962
|
+
});
|
|
110963
|
+
if (id.bundle)
|
|
110964
|
+
this.#bundle = id.bundle;
|
|
110965
|
+
} catch (e) {
|
|
110966
|
+
this.#engine = null;
|
|
110967
|
+
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110968
|
+
return { ok: false, reason: this.#lastError };
|
|
110969
|
+
}
|
|
110970
|
+
} else {
|
|
110971
|
+
try {
|
|
110972
|
+
this.#engine = new meshCore.MeshEngine(Buffer.from(id.genesis), Buffer.from(id.staticPrivate), Buffer.from(id.cert), 0, Buffer.alloc(16));
|
|
110973
|
+
if (id.bundle) {
|
|
110974
|
+
this.#engine.setBundle(Buffer.from(id.bundle), Date.now());
|
|
110975
|
+
this.#bundle = id.bundle;
|
|
110976
|
+
}
|
|
110977
|
+
} catch (e) {
|
|
110978
|
+
this.#engine = null;
|
|
110979
|
+
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110980
|
+
return { ok: false, reason: this.#lastError };
|
|
110447
110981
|
}
|
|
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
110982
|
}
|
|
110453
110983
|
this.#identity = id;
|
|
110454
|
-
|
|
110455
|
-
|
|
110984
|
+
if (!inNetd) {
|
|
110985
|
+
this.#openSocket();
|
|
110986
|
+
this.#startLan();
|
|
110987
|
+
}
|
|
110456
110988
|
this.#offRejoin = onMeshRejoin(() => this.#join());
|
|
110457
110989
|
this.#publishStatus();
|
|
110458
110990
|
this.#statusTimer = setInterval(() => this.#publishStatus(), STATUS_REFRESH_MS);
|
|
@@ -110460,6 +110992,9 @@ var MeshNode = class {
|
|
|
110460
110992
|
this.#subscribe();
|
|
110461
110993
|
this.#timer = setInterval(() => this.#tick(), TICK_MS2);
|
|
110462
110994
|
this.#timer.unref?.();
|
|
110995
|
+
void this.#refreshBundle();
|
|
110996
|
+
this.#refreshTimer = setInterval(() => void this.#refreshBundle(), REFRESH_INTERVAL_MS);
|
|
110997
|
+
this.#refreshTimer.unref?.();
|
|
110463
110998
|
return { ok: true };
|
|
110464
110999
|
}
|
|
110465
111000
|
/** Tear down. Idempotent, and safe to call from a signal handler. */
|
|
@@ -110468,6 +111003,16 @@ var MeshNode = class {
|
|
|
110468
111003
|
clearInterval(this.#timer);
|
|
110469
111004
|
this.#timer = null;
|
|
110470
111005
|
}
|
|
111006
|
+
if (this.#refreshTimer) {
|
|
111007
|
+
clearInterval(this.#refreshTimer);
|
|
111008
|
+
this.#refreshTimer = null;
|
|
111009
|
+
}
|
|
111010
|
+
if (this.#engine instanceof NetdEngine) {
|
|
111011
|
+
try {
|
|
111012
|
+
this.#engine.stop();
|
|
111013
|
+
} catch {
|
|
111014
|
+
}
|
|
111015
|
+
}
|
|
110471
111016
|
this.#unsubscribe?.();
|
|
110472
111017
|
this.#unsubscribe = null;
|
|
110473
111018
|
this.#offRejoin?.();
|
|
@@ -110567,26 +111112,34 @@ var MeshNode = class {
|
|
|
110567
111112
|
staticPub: engine.localStaticPub(),
|
|
110568
111113
|
port: () => this.#port,
|
|
110569
111114
|
epoch: () => engine.policyEpoch(),
|
|
110570
|
-
onPeer: (staticPub, address, port) => this.#learnLanPeer(staticPub, address, port)
|
|
111115
|
+
onPeer: (staticPub, address, port, epoch2) => this.#learnLanPeer(staticPub, address, port, epoch2)
|
|
110571
111116
|
});
|
|
110572
111117
|
this.#lan.start();
|
|
110573
111118
|
} catch {
|
|
110574
111119
|
this.#lan = null;
|
|
110575
111120
|
}
|
|
110576
111121
|
}
|
|
110577
|
-
/** A beacon arrived. Treated exactly like a relay hint — a candidate, not a fact.
|
|
110578
|
-
|
|
111122
|
+
/** A beacon arrived. Treated exactly like a relay hint — a candidate, not a fact.
|
|
111123
|
+
*
|
|
111124
|
+
* Including its EPOCH. The beacon has always carried one (`lan.ts`: "port(2) | epoch(8)")
|
|
111125
|
+
* for the same reason the relay hint does — so a peer that is behind can be brought up
|
|
111126
|
+
* to date — and, like the relay hint's, it was thrown away here. Two laptops on one
|
|
111127
|
+
* Wi-Fi with the internet down are the demonstration that the overlay is not
|
|
111128
|
+
* relay-dependent; without this they would find each other and then never agree on who
|
|
111129
|
+
* else exists. */
|
|
111130
|
+
#learnLanPeer(staticPub, address, port, epoch2 = 0) {
|
|
110579
111131
|
const engine = this.#engine;
|
|
110580
111132
|
if (!engine)
|
|
110581
111133
|
return;
|
|
110582
111134
|
const hex6 = staticPub.toString("hex");
|
|
111135
|
+
this.#offerBundleTo(hex6, epoch2);
|
|
110583
111136
|
try {
|
|
110584
111137
|
if (!this.#peers.has(hex6)) {
|
|
110585
111138
|
engine.addPeer(staticPub, 0, Buffer.alloc(16));
|
|
110586
111139
|
this.#peers.set(hex6, staticPub);
|
|
110587
111140
|
}
|
|
110588
111141
|
engine.addPath(staticPub, `${address}:${port}`, false);
|
|
110589
|
-
engine.
|
|
111142
|
+
engine.ensureHandshake(staticPub, Date.now());
|
|
110590
111143
|
this.#drain();
|
|
110591
111144
|
} catch (e) {
|
|
110592
111145
|
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
@@ -110671,7 +111224,7 @@ var MeshNode = class {
|
|
|
110671
111224
|
} catch {
|
|
110672
111225
|
}
|
|
110673
111226
|
}
|
|
110674
|
-
engine.
|
|
111227
|
+
engine.ensureHandshake(pk, Date.now());
|
|
110675
111228
|
break;
|
|
110676
111229
|
}
|
|
110677
111230
|
case "mesh:gone": {
|
|
@@ -110701,6 +111254,47 @@ var MeshNode = class {
|
|
|
110701
111254
|
this.#lastError = e instanceof Error ? e.message : String(e);
|
|
110702
111255
|
}
|
|
110703
111256
|
}
|
|
111257
|
+
/**
|
|
111258
|
+
* Ask the server for current policy, and adopt it if it is newer.
|
|
111259
|
+
*
|
|
111260
|
+
* The one path that can deliver an EVICTION. Gossip only ever moves a network to the
|
|
111261
|
+
* newest bundle some connected node already holds, and after an eviction no node holds
|
|
111262
|
+
* the new one — so without this, "remove that laptop" changed a database row and nothing
|
|
111263
|
+
* else until somebody happened to join.
|
|
111264
|
+
*
|
|
111265
|
+
* Applied through exactly the same steps as a gossiped bundle, deliberately: the engine
|
|
111266
|
+
* verifies it against genesis (so a hostile server cannot widen policy any more than a
|
|
111267
|
+
* hostile relay can), `#stopIfRevoked` reads our own serial out of it, it is cached to
|
|
111268
|
+
* disk, and the offer ledger resets so our peers hear about it too. That last part is
|
|
111269
|
+
* what makes one node's poll benefit the whole network.
|
|
111270
|
+
*/
|
|
111271
|
+
async #refreshBundle() {
|
|
111272
|
+
const engine = this.#engine;
|
|
111273
|
+
const id = this.#identity;
|
|
111274
|
+
if (!engine || !id?.sigPrivate)
|
|
111275
|
+
return;
|
|
111276
|
+
const meshDir2 = meshDirNameFromWireId(engine.meshId());
|
|
111277
|
+
const origin = (meshDir2 ? readLocal(meshDir2)?.origin : void 0) ?? readCredentials()?.apiOrigin;
|
|
111278
|
+
if (!origin)
|
|
111279
|
+
return;
|
|
111280
|
+
const got = await fetchBundle({
|
|
111281
|
+
origin,
|
|
111282
|
+
genesisFp: engine.meshId(),
|
|
111283
|
+
staticPub: Buffer.from(engine.localStaticPub()).toString("hex"),
|
|
111284
|
+
sigPrivate: id.sigPrivate
|
|
111285
|
+
});
|
|
111286
|
+
if (!got.bundle)
|
|
111287
|
+
return;
|
|
111288
|
+
try {
|
|
111289
|
+
engine.setBundle(Buffer.from(got.bundle), Date.now());
|
|
111290
|
+
} catch {
|
|
111291
|
+
return;
|
|
111292
|
+
}
|
|
111293
|
+
this.#stopIfRevoked(engine);
|
|
111294
|
+
cacheBundle(got.bundle, meshDir2 ?? void 0);
|
|
111295
|
+
this.#bundle = got.bundle;
|
|
111296
|
+
this.#bundleOffered.reset();
|
|
111297
|
+
}
|
|
110704
111298
|
/**
|
|
110705
111299
|
* Offer our policy bundle to a peer whose epoch is older than ours.
|
|
110706
111300
|
*
|
|
@@ -110774,7 +111368,7 @@ var MeshNode = class {
|
|
|
110774
111368
|
for (const e of p.endpoints)
|
|
110775
111369
|
engine.addPath(pk, `${p.observedIp}:${e.port}`, false);
|
|
110776
111370
|
}
|
|
110777
|
-
engine.
|
|
111371
|
+
engine.ensureHandshake(pk, Date.now());
|
|
110778
111372
|
const meshId = this.#engine?.meshId();
|
|
110779
111373
|
try {
|
|
110780
111374
|
if (meshId)
|
|
@@ -110795,10 +111389,12 @@ var MeshNode = class {
|
|
|
110795
111389
|
/** Flush everything the engine wants to send, and absorb its events. */
|
|
110796
111390
|
#drain() {
|
|
110797
111391
|
const engine = this.#engine;
|
|
110798
|
-
|
|
110799
|
-
if (!engine || !sock)
|
|
111392
|
+
if (!engine)
|
|
110800
111393
|
return;
|
|
111394
|
+
const sock = this.#sock;
|
|
110801
111395
|
for (; ; ) {
|
|
111396
|
+
if (!sock)
|
|
111397
|
+
break;
|
|
110802
111398
|
const item = engine.pollSend();
|
|
110803
111399
|
if (!item)
|
|
110804
111400
|
break;
|
|
@@ -110946,148 +111542,6 @@ function meshManager() {
|
|
|
110946
111542
|
return singleton3;
|
|
110947
111543
|
}
|
|
110948
111544
|
|
|
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
111545
|
// ../../packages/host-core/dist/mesh/route-sync.js
|
|
111092
111546
|
async function syncRoutes(running2, log9 = () => {
|
|
111093
111547
|
}) {
|
|
@@ -111116,7 +111570,14 @@ async function syncRoutes(running2, log9 = () => {
|
|
|
111116
111570
|
// The per-machine choice, and `=== true` rather than a truthiness check: an absent or
|
|
111117
111571
|
// malformed field must read as NO. netd unions this across meshes itself — any mesh
|
|
111118
111572
|
// asking for a full tunnel makes it one for the machine — so this stays per mesh here.
|
|
111119
|
-
fullTunnel: readLocal(meshId)?.fullTunnel === true
|
|
111573
|
+
fullTunnel: readLocal(meshId)?.fullTunnel === true,
|
|
111574
|
+
// THE KEY, and the bundle. With these netd runs the node — the data plane — rather
|
|
111575
|
+
// than only pointing routes at a device nothing reads. The crate's own doc always
|
|
111576
|
+
// described the enrolment as "a genesis block, a certificate and a key"; this is the
|
|
111577
|
+
// first caller to send the third. Over the helper's authenticated socket, to the one
|
|
111578
|
+
// process on the machine that already holds the device the traffic goes into.
|
|
111579
|
+
staticPrivate: identity.staticPrivate,
|
|
111580
|
+
...identity.bundle ? { bundle: identity.bundle } : {}
|
|
111120
111581
|
});
|
|
111121
111582
|
if (r.ok) {
|
|
111122
111583
|
out.up.push(meshId);
|
|
@@ -111142,22 +111603,63 @@ async function syncRoutes(running2, log9 = () => {
|
|
|
111142
111603
|
}
|
|
111143
111604
|
|
|
111144
111605
|
// ../../packages/host-core/dist/mesh/start-meshes.js
|
|
111145
|
-
|
|
111606
|
+
var ROUTE_RETRY_MS = 6e4;
|
|
111607
|
+
function startMeshes(log9, opts = {}) {
|
|
111146
111608
|
const running2 = startNodes(log9);
|
|
111147
|
-
|
|
111609
|
+
const retryMs = opts.retryMs ?? ROUTE_RETRY_MS;
|
|
111610
|
+
let timer2 = null;
|
|
111611
|
+
let stopped2 = false;
|
|
111612
|
+
let lastSummary = "";
|
|
111613
|
+
const attempt = async () => {
|
|
111614
|
+
let r;
|
|
111615
|
+
try {
|
|
111616
|
+
r = await syncRoutes(running2, log9);
|
|
111617
|
+
} catch (e) {
|
|
111618
|
+
log9(`routes: sync threw \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
111619
|
+
return false;
|
|
111620
|
+
}
|
|
111148
111621
|
if (r.helperAbsent) {
|
|
111149
|
-
|
|
111150
|
-
|
|
111622
|
+
const msg = "routes: the network helper is not installed \u2014 the overlay carries no traffic yet";
|
|
111623
|
+
if (msg !== lastSummary)
|
|
111624
|
+
log9(msg);
|
|
111625
|
+
lastSummary = msg;
|
|
111626
|
+
return false;
|
|
111151
111627
|
}
|
|
111152
111628
|
if (r.up.length)
|
|
111153
111629
|
log9(`routes: installed for ${r.up.join(", ")}`);
|
|
111154
111630
|
if (r.down.length)
|
|
111155
111631
|
log9(`routes: removed for ${r.down.join(", ")}`);
|
|
111156
|
-
|
|
111157
|
-
|
|
111158
|
-
|
|
111159
|
-
|
|
111632
|
+
const failures2 = r.failed.map((f) => `routes: ${f.meshId} refused \u2014 ${f.reason}`).join("\n");
|
|
111633
|
+
if (failures2 && failures2 !== lastSummary)
|
|
111634
|
+
log9(failures2);
|
|
111635
|
+
lastSummary = failures2;
|
|
111636
|
+
return r.failed.length === 0;
|
|
111637
|
+
};
|
|
111638
|
+
const schedule = () => {
|
|
111639
|
+
if (stopped2 || running2.length === 0)
|
|
111640
|
+
return;
|
|
111641
|
+
timer2 = setTimeout(() => {
|
|
111642
|
+
timer2 = null;
|
|
111643
|
+
void attempt().then((done) => {
|
|
111644
|
+
if (!done)
|
|
111645
|
+
schedule();
|
|
111646
|
+
});
|
|
111647
|
+
}, retryMs);
|
|
111648
|
+
timer2.unref?.();
|
|
111649
|
+
};
|
|
111650
|
+
void attempt().then((done) => {
|
|
111651
|
+
if (!done)
|
|
111652
|
+
schedule();
|
|
111160
111653
|
});
|
|
111654
|
+
return {
|
|
111655
|
+
stop() {
|
|
111656
|
+
stopped2 = true;
|
|
111657
|
+
if (timer2) {
|
|
111658
|
+
clearTimeout(timer2);
|
|
111659
|
+
timer2 = null;
|
|
111660
|
+
}
|
|
111661
|
+
}
|
|
111662
|
+
};
|
|
111161
111663
|
}
|
|
111162
111664
|
function startNodes(log9) {
|
|
111163
111665
|
const ids = listMeshIds();
|
|
@@ -112487,7 +112989,7 @@ function appendRdeskAudit(e) {
|
|
|
112487
112989
|
|
|
112488
112990
|
// ../../packages/host-core/dist/fileprovider-bridge.js
|
|
112489
112991
|
init_managed_spawn();
|
|
112490
|
-
import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync37, rmSync as rmSync8, existsSync as
|
|
112992
|
+
import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync37, rmSync as rmSync8, existsSync as existsSync35 } from "node:fs";
|
|
112491
112993
|
import { homedir as homedir10 } from "node:os";
|
|
112492
112994
|
import { join as join73 } from "node:path";
|
|
112493
112995
|
init_safe_kill();
|
|
@@ -112658,7 +113160,7 @@ function stopFileProviderBridge() {
|
|
|
112658
113160
|
|
|
112659
113161
|
// ../../packages/host-core/dist/vault/autofill-bridge.js
|
|
112660
113162
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
112661
|
-
import { existsSync as
|
|
113163
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync38, writeFileSync as writeFileSync37, rmSync as rmSync9 } from "node:fs";
|
|
112662
113164
|
import { homedir as homedir11 } from "node:os";
|
|
112663
113165
|
import { join as join74 } from "node:path";
|
|
112664
113166
|
|
|
@@ -112733,7 +113235,7 @@ function writeBridgeInfo(port, token3, log9) {
|
|
|
112733
113235
|
return;
|
|
112734
113236
|
const containerData = appexContainerData();
|
|
112735
113237
|
try {
|
|
112736
|
-
if (!
|
|
113238
|
+
if (!existsSync36(containerData)) {
|
|
112737
113239
|
if (!infoLoggedOnce) {
|
|
112738
113240
|
infoLoggedOnce = true;
|
|
112739
113241
|
log9("autofill bridge-info SKIP: no appex container yet at", containerData);
|
|
@@ -112982,7 +113484,7 @@ function createNodePowerController() {
|
|
|
112982
113484
|
|
|
112983
113485
|
// ../../packages/host-core/dist/native-host.js
|
|
112984
113486
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
112985
|
-
import { chmodSync as chmodSync6, existsSync as
|
|
113487
|
+
import { chmodSync as chmodSync6, existsSync as existsSync37, mkdirSync as mkdirSync39, writeFileSync as writeFileSync38 } from "node:fs";
|
|
112986
113488
|
import { homedir as homedir12, platform as platform5 } from "node:os";
|
|
112987
113489
|
import { dirname as dirname34, join as join75, resolve as resolve12 } from "node:path";
|
|
112988
113490
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
@@ -113013,7 +113515,7 @@ function resolveBridge(log9) {
|
|
|
113013
113515
|
} catch {
|
|
113014
113516
|
}
|
|
113015
113517
|
for (const c of candidates)
|
|
113016
|
-
if (c &&
|
|
113518
|
+
if (c && existsSync37(c))
|
|
113017
113519
|
return c;
|
|
113018
113520
|
log9("companion native-host: bridge not found; skipping registration (looked in", candidates.filter(Boolean).join(" , "), ")");
|
|
113019
113521
|
return null;
|
|
@@ -113055,7 +113557,7 @@ function registerNativeHost(opts) {
|
|
|
113055
113557
|
return registerWindows(opts.daemonDir, manifestJson, log9);
|
|
113056
113558
|
let wrote = 0;
|
|
113057
113559
|
for (const profile of browserProfileDirs()) {
|
|
113058
|
-
if (!
|
|
113560
|
+
if (!existsSync37(profile))
|
|
113059
113561
|
continue;
|
|
113060
113562
|
try {
|
|
113061
113563
|
const dir2 = join75(profile, "NativeMessagingHosts");
|
|
@@ -113091,7 +113593,7 @@ init_daemon_settings();
|
|
|
113091
113593
|
|
|
113092
113594
|
// ../../packages/host-core/dist/activity/activity-tracker.js
|
|
113093
113595
|
init_credentials();
|
|
113094
|
-
import { promises as fsp, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, existsSync as
|
|
113596
|
+
import { promises as fsp, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, existsSync as existsSync38 } from "node:fs";
|
|
113095
113597
|
import { join as join76 } from "node:path";
|
|
113096
113598
|
function activityProfilePath() {
|
|
113097
113599
|
return join76(daemonDir2(), "activity-profile.json");
|
|
@@ -113169,7 +113671,7 @@ function createActivityTracker(opts = {}) {
|
|
|
113169
113671
|
return;
|
|
113170
113672
|
const key2 = front.bundleId || front.name;
|
|
113171
113673
|
await ensureLoaded();
|
|
113172
|
-
if (profile && Object.keys(profile.apps).length && !
|
|
113674
|
+
if (profile && Object.keys(profile.apps).length && !existsSync38(activityProfilePath())) {
|
|
113173
113675
|
log9("activity profile cleared externally \u2014 resetting in-memory");
|
|
113174
113676
|
profile = { version: 1, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), apps: {} };
|
|
113175
113677
|
}
|
|
@@ -113402,7 +113904,7 @@ function backoff2() {
|
|
|
113402
113904
|
|
|
113403
113905
|
// ../../packages/host-core/dist/daemon-runtime.js
|
|
113404
113906
|
var daemonClipboardSync = null;
|
|
113405
|
-
var
|
|
113907
|
+
var REFRESH_INTERVAL_MS2 = 12 * 60 * 60 * 1e3;
|
|
113406
113908
|
async function runDaemon(opts = {}) {
|
|
113407
113909
|
const VERSION3 = opts.version ?? process.env.CCB_DAEMON_VERSION ?? "dev";
|
|
113408
113910
|
const TAG = opts.tag ?? "host-daemon";
|
|
@@ -113443,7 +113945,7 @@ async function runDaemon(opts = {}) {
|
|
|
113443
113945
|
function acquireLock2() {
|
|
113444
113946
|
const f = pidfile();
|
|
113445
113947
|
try {
|
|
113446
|
-
if (!
|
|
113948
|
+
if (!existsSync39(daemonDir2()))
|
|
113447
113949
|
mkdirSync41(daemonDir2(), { recursive: true, mode: 448 });
|
|
113448
113950
|
} catch {
|
|
113449
113951
|
}
|
|
@@ -113469,7 +113971,7 @@ async function runDaemon(opts = {}) {
|
|
|
113469
113971
|
function releaseLock() {
|
|
113470
113972
|
try {
|
|
113471
113973
|
const f = pidfile();
|
|
113472
|
-
if (
|
|
113974
|
+
if (existsSync39(f) && Number(readFileSync49(f, "utf-8").trim()) === process.pid)
|
|
113473
113975
|
unlinkSync6(f);
|
|
113474
113976
|
} catch {
|
|
113475
113977
|
}
|
|
@@ -113511,6 +114013,7 @@ async function runDaemon(opts = {}) {
|
|
|
113511
114013
|
}
|
|
113512
114014
|
}
|
|
113513
114015
|
let stopGatewayKeyRefresh = null;
|
|
114016
|
+
let meshRoutes = null;
|
|
113514
114017
|
let timer2 = null;
|
|
113515
114018
|
let identityWatch = null;
|
|
113516
114019
|
let refreshRetry = null;
|
|
@@ -113605,6 +114108,10 @@ async function runDaemon(opts = {}) {
|
|
|
113605
114108
|
stopGatewayKeyRefresh();
|
|
113606
114109
|
stopGatewayKeyRefresh = null;
|
|
113607
114110
|
}
|
|
114111
|
+
if (meshRoutes) {
|
|
114112
|
+
meshRoutes.stop();
|
|
114113
|
+
meshRoutes = null;
|
|
114114
|
+
}
|
|
113608
114115
|
try {
|
|
113609
114116
|
offRecovery?.();
|
|
113610
114117
|
offRecovery = null;
|
|
@@ -114296,7 +114803,7 @@ async function runDaemon(opts = {}) {
|
|
|
114296
114803
|
} catch {
|
|
114297
114804
|
}
|
|
114298
114805
|
try {
|
|
114299
|
-
startMeshes(log9);
|
|
114806
|
+
meshRoutes = startMeshes(log9);
|
|
114300
114807
|
} catch {
|
|
114301
114808
|
}
|
|
114302
114809
|
writeStatus2({ deviceId: c.deviceId, connected: true });
|
|
@@ -114575,7 +115082,7 @@ async function runDaemon(opts = {}) {
|
|
|
114575
115082
|
const daemonLogFile = join77(daemonDir2(), "daemon.log");
|
|
114576
115083
|
const capTimer = setInterval(() => {
|
|
114577
115084
|
try {
|
|
114578
|
-
if (
|
|
115085
|
+
if (existsSync39(daemonLogFile) && statSync14(daemonLogFile).size > DAEMON_LOG_CAP) {
|
|
114579
115086
|
const buf = readFileSync49(daemonLogFile, "utf-8");
|
|
114580
115087
|
const kept = `\u2026[daemon.log capped at ${(/* @__PURE__ */ new Date()).toISOString()}]\u2026
|
|
114581
115088
|
` + buf.slice(-DAEMON_LOG_CAP / 2);
|
|
@@ -114592,7 +115099,7 @@ async function runDaemon(opts = {}) {
|
|
|
114592
115099
|
startAutofillBridge(log9);
|
|
114593
115100
|
}
|
|
114594
115101
|
if (ownsMachine)
|
|
114595
|
-
startMeshes(log9);
|
|
115102
|
+
meshRoutes = startMeshes(log9);
|
|
114596
115103
|
if (ownsMachine) {
|
|
114597
115104
|
try {
|
|
114598
115105
|
stopGatewayKeyRefresh = startGatewayKeyRefresh();
|
|
@@ -114604,7 +115111,7 @@ async function runDaemon(opts = {}) {
|
|
|
114604
115111
|
await refresh();
|
|
114605
115112
|
timer2 = setInterval(() => {
|
|
114606
115113
|
void refresh();
|
|
114607
|
-
},
|
|
115114
|
+
}, REFRESH_INTERVAL_MS2);
|
|
114608
115115
|
}
|
|
114609
115116
|
|
|
114610
115117
|
// ../../packages/host-core/dist/host-daemon-entry.js
|
|
@@ -114714,7 +115221,7 @@ async function evictNode(args) {
|
|
|
114714
115221
|
const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}`, { method: "DELETE", body: {} });
|
|
114715
115222
|
return r.ok ? { ok: true, epoch: r.data.epoch } : r;
|
|
114716
115223
|
}
|
|
114717
|
-
async function enrolWith(requested, post) {
|
|
115224
|
+
async function enrolWith(requested, post, origin) {
|
|
114718
115225
|
const name = normaliseNodeName(requested);
|
|
114719
115226
|
if (!name) {
|
|
114720
115227
|
return fail3("bad-name", `"${requested}" cannot be a machine name \u2014 names are DNS labels, so letters, digits and hyphens only`);
|
|
@@ -114738,7 +115245,7 @@ async function enrolWith(requested, post) {
|
|
|
114738
115245
|
}
|
|
114739
115246
|
try {
|
|
114740
115247
|
saveMesh(meshId, { genesis, cert, staticPrivate, sigPrivate });
|
|
114741
|
-
writeLocal(meshId, { joinedAt: Date.now(), enabled: true });
|
|
115248
|
+
writeLocal(meshId, { joinedAt: Date.now(), enabled: true, ...origin ? { origin } : {} });
|
|
114742
115249
|
if (r.data.bundle) {
|
|
114743
115250
|
try {
|
|
114744
115251
|
cacheBundle(fromHexOrB64(r.data.bundle), meshId);
|
|
@@ -114760,16 +115267,24 @@ async function enrolWith(requested, post) {
|
|
|
114760
115267
|
};
|
|
114761
115268
|
}
|
|
114762
115269
|
async function enrol(args) {
|
|
114763
|
-
return enrolWith(
|
|
114764
|
-
|
|
114765
|
-
|
|
114766
|
-
|
|
115270
|
+
return enrolWith(
|
|
115271
|
+
args.name,
|
|
115272
|
+
(staticPub, sigPub, name) => call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes`, {
|
|
115273
|
+
method: "POST",
|
|
115274
|
+
body: { name, staticPub, sigPub, ...args.exitNode === true ? { exitNode: true } : {} }
|
|
115275
|
+
}),
|
|
115276
|
+
// This path is authenticated, so the origin is necessarily the signed-in one.
|
|
115277
|
+
resolveOrigin(void 0)
|
|
115278
|
+
);
|
|
114767
115279
|
}
|
|
114768
115280
|
async function joinWithToken(args) {
|
|
114769
|
-
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { token: args.token, name, staticPub, sigPub }));
|
|
115281
|
+
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { token: args.token, name, staticPub, sigPub }), resolveOrigin(args.origin));
|
|
115282
|
+
}
|
|
115283
|
+
function resolveOrigin(origin) {
|
|
115284
|
+
return origin ?? readCredentials()?.apiOrigin ?? void 0;
|
|
114770
115285
|
}
|
|
114771
115286
|
async function postJoin(origin, body) {
|
|
114772
|
-
const base = origin
|
|
115287
|
+
const base = resolveOrigin(origin);
|
|
114773
115288
|
if (!base) {
|
|
114774
115289
|
return fail3("not-signed-in", "this machine has never signed in \u2014 pass --origin https://\u2026 so it knows which server to ask");
|
|
114775
115290
|
}
|
|
@@ -114797,7 +115312,7 @@ async function postJoin(origin, body) {
|
|
|
114797
115312
|
return { ok: true, data: JSON.parse(text12) };
|
|
114798
115313
|
}
|
|
114799
115314
|
async function enrolWithCode(args) {
|
|
114800
|
-
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { code: args.code, name, staticPub, sigPub }));
|
|
115315
|
+
return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { code: args.code, name, staticPub, sigPub }), resolveOrigin(args.origin));
|
|
114801
115316
|
}
|
|
114802
115317
|
async function rawPrivate(key2) {
|
|
114803
115318
|
const pkcs8 = new Uint8Array(await crypto.subtle.exportKey("pkcs8", key2));
|
|
@@ -114881,13 +115396,13 @@ init_credentials();
|
|
|
114881
115396
|
|
|
114882
115397
|
// ../../packages/host-core/dist/net-service/ensure-installed.js
|
|
114883
115398
|
import { execFile as execFile14 } from "node:child_process";
|
|
114884
|
-
import { existsSync as
|
|
115399
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
114885
115400
|
import { dirname as dirname36, join as join81 } from "node:path";
|
|
114886
115401
|
import { promisify as promisify10 } from "node:util";
|
|
114887
115402
|
|
|
114888
115403
|
// ../../packages/host-core/dist/net-service/launchd-system.js
|
|
114889
115404
|
import { spawn as spawn9 } from "node:child_process";
|
|
114890
|
-
import { existsSync as
|
|
115405
|
+
import { existsSync as existsSync40, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync41, rmSync as rmSync10, readFileSync as readFileSync50 } from "node:fs";
|
|
114891
115406
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
114892
115407
|
import { join as join78 } from "node:path";
|
|
114893
115408
|
|
|
@@ -115058,7 +115573,7 @@ ${plist}TESSERACT_PLIST_EOF`,
|
|
|
115058
115573
|
};
|
|
115059
115574
|
},
|
|
115060
115575
|
async state() {
|
|
115061
|
-
if (!
|
|
115576
|
+
if (!existsSync40(PLIST))
|
|
115062
115577
|
return { installed: false, running: false };
|
|
115063
115578
|
const owner = parseOwnerUid(readFileSync50(PLIST, "utf8"));
|
|
115064
115579
|
const running2 = await netdAvailable();
|
|
@@ -115078,7 +115593,7 @@ ${plist}TESSERACT_PLIST_EOF`,
|
|
|
115078
115593
|
|
|
115079
115594
|
// ../../packages/host-core/dist/net-service/systemd-system.js
|
|
115080
115595
|
import { spawn as spawn11 } from "node:child_process";
|
|
115081
|
-
import { existsSync as
|
|
115596
|
+
import { existsSync as existsSync41, readFileSync as readFileSync51 } from "node:fs";
|
|
115082
115597
|
|
|
115083
115598
|
// ../../packages/host-core/dist/service/exec.js
|
|
115084
115599
|
import { execFile as execFile11, spawn as spawn10 } from "node:child_process";
|
|
@@ -115221,7 +115736,7 @@ function makeSystemdSystem() {
|
|
|
115221
115736
|
return code === 0 ? { ok: true } : { ok: false, detail: `removing the helper failed (exit ${code})` };
|
|
115222
115737
|
},
|
|
115223
115738
|
async state() {
|
|
115224
|
-
if (!
|
|
115739
|
+
if (!existsSync41(UNIT_PATH))
|
|
115225
115740
|
return { installed: false, running: false };
|
|
115226
115741
|
const owner = parseOwnerUid(readFileSync51(UNIT_PATH, "utf8"));
|
|
115227
115742
|
const active = await tryRun("systemctl", ["is-active", UNIT]);
|
|
@@ -115484,7 +115999,7 @@ function makeNetService() {
|
|
|
115484
115999
|
}
|
|
115485
116000
|
|
|
115486
116001
|
// ../../packages/host-core/dist/net-service/netd-binary.js
|
|
115487
|
-
import { existsSync as
|
|
116002
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
115488
116003
|
import { dirname as dirname35, join as join80 } from "node:path";
|
|
115489
116004
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
115490
116005
|
function netdBinaryName() {
|
|
@@ -115492,7 +116007,7 @@ function netdBinaryName() {
|
|
|
115492
116007
|
}
|
|
115493
116008
|
function override2() {
|
|
115494
116009
|
const p = process.env.CCB_NETD_BIN;
|
|
115495
|
-
return p &&
|
|
116010
|
+
return p && existsSync42(p) ? p : null;
|
|
115496
116011
|
}
|
|
115497
116012
|
function netdBinaryPath() {
|
|
115498
116013
|
const fromEnv = override2();
|
|
@@ -115519,7 +116034,7 @@ function netdBinaryPath() {
|
|
|
115519
116034
|
candidates.push(join80(process.cwd(), "crates", "target", "release", name));
|
|
115520
116035
|
for (const c of candidates) {
|
|
115521
116036
|
try {
|
|
115522
|
-
if (
|
|
116037
|
+
if (existsSync42(c))
|
|
115523
116038
|
return c;
|
|
115524
116039
|
} catch {
|
|
115525
116040
|
}
|
|
@@ -115561,7 +116076,7 @@ async function ensureNetHelperInstalled() {
|
|
|
115561
116076
|
if (st.installed && !mismatched)
|
|
115562
116077
|
return { ok: true, already: true };
|
|
115563
116078
|
const exec2 = netdBinaryPath();
|
|
115564
|
-
if (exec2 && process.platform === "win32" && !
|
|
116079
|
+
if (exec2 && process.platform === "win32" && !existsSync43(join81(dirname36(exec2), "wintun.dll"))) {
|
|
115565
116080
|
return {
|
|
115566
116081
|
ok: false,
|
|
115567
116082
|
reason: "no-binary",
|
|
@@ -115613,7 +116128,7 @@ import { platform as platform6 } from "node:os";
|
|
|
115613
116128
|
|
|
115614
116129
|
// ../../packages/host-core/dist/service/launchd.js
|
|
115615
116130
|
init_credentials();
|
|
115616
|
-
import { writeFileSync as writeFileSync43, existsSync as
|
|
116131
|
+
import { writeFileSync as writeFileSync43, existsSync as existsSync44, mkdirSync as mkdirSync42, unlinkSync as unlinkSync7 } from "node:fs";
|
|
115617
116132
|
import { dirname as dirname37, join as join82 } from "node:path";
|
|
115618
116133
|
import { homedir as homedir13, userInfo as userInfo2 } from "node:os";
|
|
115619
116134
|
function xml2(s) {
|
|
@@ -115668,6 +116183,36 @@ ${env}
|
|
|
115668
116183
|
</plist>
|
|
115669
116184
|
`;
|
|
115670
116185
|
}
|
|
116186
|
+
const loaded = async () => {
|
|
116187
|
+
try {
|
|
116188
|
+
await run5("launchctl", ["print", serviceTarget()]);
|
|
116189
|
+
return true;
|
|
116190
|
+
} catch {
|
|
116191
|
+
return false;
|
|
116192
|
+
}
|
|
116193
|
+
};
|
|
116194
|
+
const untilGone = async () => {
|
|
116195
|
+
for (let i = 0; i < 25; i++) {
|
|
116196
|
+
if (!await loaded())
|
|
116197
|
+
return;
|
|
116198
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
116199
|
+
}
|
|
116200
|
+
};
|
|
116201
|
+
const bootstrapWithRetry = async () => {
|
|
116202
|
+
let last;
|
|
116203
|
+
for (let i = 0; i < 5; i++) {
|
|
116204
|
+
try {
|
|
116205
|
+
await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]);
|
|
116206
|
+
return;
|
|
116207
|
+
} catch (e) {
|
|
116208
|
+
last = e;
|
|
116209
|
+
if (await loaded())
|
|
116210
|
+
return;
|
|
116211
|
+
await new Promise((r) => setTimeout(r, 300 * (i + 1)));
|
|
116212
|
+
}
|
|
116213
|
+
}
|
|
116214
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
116215
|
+
};
|
|
115671
116216
|
return {
|
|
115672
116217
|
async install(spec) {
|
|
115673
116218
|
mkdirSync42(workDirOf(spec), { recursive: true });
|
|
@@ -115676,16 +116221,20 @@ ${env}
|
|
|
115676
116221
|
writeFileSync43(plistPath(), buildPlist2(spec));
|
|
115677
116222
|
await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
|
|
115678
116223
|
});
|
|
115679
|
-
await
|
|
116224
|
+
await untilGone();
|
|
116225
|
+
await bootstrapWithRetry();
|
|
115680
116226
|
await run5("launchctl", ["enable", serviceTarget()]).catch(() => {
|
|
115681
116227
|
});
|
|
115682
116228
|
await run5("launchctl", ["kickstart", "-k", serviceTarget()]).catch(() => {
|
|
115683
116229
|
});
|
|
116230
|
+
if (!await loaded()) {
|
|
116231
|
+
throw new Error(`the service ${label} is not loaded after install \u2014 check \`launchctl print ${serviceTarget()}\``);
|
|
116232
|
+
}
|
|
115684
116233
|
},
|
|
115685
116234
|
async uninstall() {
|
|
115686
116235
|
await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
|
|
115687
116236
|
});
|
|
115688
|
-
if (
|
|
116237
|
+
if (existsSync44(plistPath())) {
|
|
115689
116238
|
try {
|
|
115690
116239
|
unlinkSync7(plistPath());
|
|
115691
116240
|
} catch {
|
|
@@ -115696,7 +116245,7 @@ ${env}
|
|
|
115696
116245
|
await this.install(spec);
|
|
115697
116246
|
},
|
|
115698
116247
|
async isInstalled() {
|
|
115699
|
-
return
|
|
116248
|
+
return existsSync44(plistPath());
|
|
115700
116249
|
},
|
|
115701
116250
|
async start() {
|
|
115702
116251
|
await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]).catch(() => {
|
|
@@ -115713,7 +116262,7 @@ ${env}
|
|
|
115713
116262
|
},
|
|
115714
116263
|
async logs(follow) {
|
|
115715
116264
|
const f = logFile();
|
|
115716
|
-
if (!
|
|
116265
|
+
if (!existsSync44(f)) {
|
|
115717
116266
|
console.log(`No log yet at ${f} \u2014 has the service started?`);
|
|
115718
116267
|
return;
|
|
115719
116268
|
}
|
|
@@ -115724,7 +116273,7 @@ ${env}
|
|
|
115724
116273
|
|
|
115725
116274
|
// ../../packages/host-core/dist/service/systemd.js
|
|
115726
116275
|
init_credentials();
|
|
115727
|
-
import { writeFileSync as writeFileSync44, existsSync as
|
|
116276
|
+
import { writeFileSync as writeFileSync44, existsSync as existsSync45, mkdirSync as mkdirSync43, unlinkSync as unlinkSync8 } from "node:fs";
|
|
115728
116277
|
import { dirname as dirname38, join as join83 } from "node:path";
|
|
115729
116278
|
import { homedir as homedir14, userInfo as userInfo3 } from "node:os";
|
|
115730
116279
|
function unitVal2(v) {
|
|
@@ -115780,7 +116329,7 @@ WantedBy=default.target
|
|
|
115780
116329
|
async uninstall() {
|
|
115781
116330
|
await run5("systemctl", ["--user", "disable", "--now", unit]).catch(() => {
|
|
115782
116331
|
});
|
|
115783
|
-
if (
|
|
116332
|
+
if (existsSync45(unitPath())) {
|
|
115784
116333
|
try {
|
|
115785
116334
|
unlinkSync8(unitPath());
|
|
115786
116335
|
} catch {
|
|
@@ -115793,7 +116342,7 @@ WantedBy=default.target
|
|
|
115793
116342
|
await this.install(spec);
|
|
115794
116343
|
},
|
|
115795
116344
|
async isInstalled() {
|
|
115796
|
-
return
|
|
116345
|
+
return existsSync45(unitPath());
|
|
115797
116346
|
},
|
|
115798
116347
|
async start() {
|
|
115799
116348
|
await run5("systemctl", ["--user", "start", unit]);
|
|
@@ -115806,7 +116355,7 @@ WantedBy=default.target
|
|
|
115806
116355
|
},
|
|
115807
116356
|
async logs(follow) {
|
|
115808
116357
|
const f = join83(daemonDir2(), "daemon.log");
|
|
115809
|
-
if (
|
|
116358
|
+
if (existsSync45(f)) {
|
|
115810
116359
|
await runInherit("tail", follow ? ["-f", f] : ["-n", "200", f]);
|
|
115811
116360
|
return;
|
|
115812
116361
|
}
|
|
@@ -115818,8 +116367,20 @@ WantedBy=default.target
|
|
|
115818
116367
|
|
|
115819
116368
|
// ../../packages/host-core/dist/service/windows.js
|
|
115820
116369
|
init_credentials();
|
|
115821
|
-
import { writeFileSync as writeFileSync45, existsSync as
|
|
116370
|
+
import { writeFileSync as writeFileSync45, existsSync as existsSync46, mkdirSync as mkdirSync44, unlinkSync as unlinkSync9, readFileSync as readFileSync52 } from "node:fs";
|
|
115822
116371
|
import { dirname as dirname39, join as join84 } from "node:path";
|
|
116372
|
+
function publishedDaemonPid(dir2) {
|
|
116373
|
+
for (const f of ["status.json", "daemon.lock"]) {
|
|
116374
|
+
try {
|
|
116375
|
+
const raw = readFileSync52(join84(dir2, f), "utf-8");
|
|
116376
|
+
const pid = f === "status.json" ? Number(JSON.parse(raw).pid) : Number(raw.trim());
|
|
116377
|
+
if (Number.isInteger(pid) && pid > 0)
|
|
116378
|
+
return pid;
|
|
116379
|
+
} catch {
|
|
116380
|
+
}
|
|
116381
|
+
}
|
|
116382
|
+
return null;
|
|
116383
|
+
}
|
|
115823
116384
|
function makeWindowsTask(instanceId) {
|
|
115824
116385
|
const suffix = instanceSuffix(instanceId);
|
|
115825
116386
|
const task = `Fineguide\\TesseractHost${suffix ? `-${suffix}` : ""}`;
|
|
@@ -115851,14 +116412,20 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
|
|
|
115851
116412
|
async uninstall() {
|
|
115852
116413
|
await run5("schtasks", ["/Delete", "/TN", task, "/F"]).catch(() => {
|
|
115853
116414
|
});
|
|
115854
|
-
if (
|
|
116415
|
+
if (existsSync46(wrapperPath())) {
|
|
115855
116416
|
try {
|
|
115856
116417
|
unlinkSync9(wrapperPath());
|
|
115857
116418
|
} catch {
|
|
115858
116419
|
}
|
|
115859
116420
|
}
|
|
115860
116421
|
},
|
|
116422
|
+
// STOP FIRST. `install` alone re-creates the task and runs it, which on Windows spawns a
|
|
116423
|
+
// SECOND daemon beside the one that is still running (see stop()); the newcomer finds the
|
|
116424
|
+
// pid lock held and stands down, so "restart" restarted nothing — the old process kept
|
|
116425
|
+
// running the old code. That is how a machine upgraded to a fixed CLI kept exhibiting the
|
|
116426
|
+
// bug the upgrade fixed, and how `tesseract-agent restart` reported success while doing it.
|
|
115861
116427
|
async restart(spec) {
|
|
116428
|
+
await this.stop();
|
|
115862
116429
|
await this.install(spec);
|
|
115863
116430
|
},
|
|
115864
116431
|
async isInstalled() {
|
|
@@ -115872,16 +116439,54 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
|
|
|
115872
116439
|
async start() {
|
|
115873
116440
|
await run5("schtasks", ["/Run", "/TN", task]);
|
|
115874
116441
|
},
|
|
116442
|
+
/**
|
|
116443
|
+
* Stop the daemon. Not the task — the daemon.
|
|
116444
|
+
*
|
|
116445
|
+
* `schtasks /End` ends the TASK's process, and the task's process is the .cmd wrapper, which
|
|
116446
|
+
* exited the instant it ran `start "" /b` to detach the daemon. So /End ended a task that had
|
|
116447
|
+
* already finished, reported success, and the daemon ran on. Every `stop`, `restart` and
|
|
116448
|
+
* self-update on Windows has been a no-op against a running daemon since the wrapper was
|
|
116449
|
+
* written; observed directly as two node processes surviving stop, restart, and the task's
|
|
116450
|
+
* own /End, with start times from the original launch.
|
|
116451
|
+
*
|
|
116452
|
+
* The daemon publishes its own pid (status.json / daemon.lock), and that is what gets ended.
|
|
116453
|
+
* Its PARENT is ended instead when the parent is the CLI supervisor (`cli.js run`), because
|
|
116454
|
+
* killing only the worker makes the supervisor respawn it; `/T` takes the whole tree either
|
|
116455
|
+
* way. The parent is checked by command line before being touched: the lock can be held by a
|
|
116456
|
+
* process that is not ours to kill — the desktop app owning the machine — and a supervisor
|
|
116457
|
+
* that is not `cli.js` is left alone, worker only.
|
|
116458
|
+
*
|
|
116459
|
+
* Best-effort throughout, like the other controllers' stop: a daemon that is already gone
|
|
116460
|
+
* is the desired state, not an error.
|
|
116461
|
+
*/
|
|
115875
116462
|
async stop() {
|
|
115876
116463
|
await run5("schtasks", ["/End", "/TN", task]).catch(() => {
|
|
115877
116464
|
});
|
|
116465
|
+
const pid = publishedDaemonPid(daemonDir2());
|
|
116466
|
+
if (pid === null)
|
|
116467
|
+
return;
|
|
116468
|
+
let target = pid;
|
|
116469
|
+
try {
|
|
116470
|
+
const { stdout } = await run5("powershell", [
|
|
116471
|
+
"-NoProfile",
|
|
116472
|
+
"-Command",
|
|
116473
|
+
`$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)" } }`
|
|
116474
|
+
]);
|
|
116475
|
+
const [ppidRaw, cmd = ""] = String(stdout).trim().split("|");
|
|
116476
|
+
const ppid = Number(ppidRaw);
|
|
116477
|
+
if (Number.isInteger(ppid) && ppid > 0 && /cli\.js["']?\s+run\b/.test(cmd))
|
|
116478
|
+
target = ppid;
|
|
116479
|
+
} catch {
|
|
116480
|
+
}
|
|
116481
|
+
await run5("taskkill", ["/pid", String(target), "/T", "/F"]).catch(() => {
|
|
116482
|
+
});
|
|
115878
116483
|
},
|
|
115879
116484
|
async status() {
|
|
115880
116485
|
await runInherit("schtasks", ["/Query", "/TN", task, "/V", "/FO", "LIST"]);
|
|
115881
116486
|
},
|
|
115882
116487
|
async logs(follow) {
|
|
115883
116488
|
const f = logFile();
|
|
115884
|
-
if (!
|
|
116489
|
+
if (!existsSync46(f)) {
|
|
115885
116490
|
console.log(`No log yet at ${f} \u2014 has the task run?`);
|
|
115886
116491
|
return;
|
|
115887
116492
|
}
|
|
@@ -115913,7 +116518,7 @@ init_safe_kill();
|
|
|
115913
116518
|
// src/auth.ts
|
|
115914
116519
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
115915
116520
|
import { randomUUID as randomUUID30 } from "node:crypto";
|
|
115916
|
-
import { existsSync as
|
|
116521
|
+
import { existsSync as existsSync47, rmSync as rmSync12 } from "node:fs";
|
|
115917
116522
|
import { join as join85 } from "node:path";
|
|
115918
116523
|
|
|
115919
116524
|
// src/config.ts
|
|
@@ -116116,7 +116721,7 @@ async function logout() {
|
|
|
116116
116721
|
for (const f of ["credentials.json", "status.json", "daemon.lock"]) {
|
|
116117
116722
|
try {
|
|
116118
116723
|
const p = join85(daemonDir2(), f);
|
|
116119
|
-
if (
|
|
116724
|
+
if (existsSync47(p)) rmSync12(p);
|
|
116120
116725
|
} catch {
|
|
116121
116726
|
}
|
|
116122
116727
|
}
|
|
@@ -116276,7 +116881,7 @@ function startSelfUpdater(current) {
|
|
|
116276
116881
|
// src/service.ts
|
|
116277
116882
|
import { join as join86 } from "node:path";
|
|
116278
116883
|
import { platform as platform7 } from "node:os";
|
|
116279
|
-
import { existsSync as
|
|
116884
|
+
import { existsSync as existsSync48, readFileSync as readFileSync53 } from "node:fs";
|
|
116280
116885
|
function controller(instanceId) {
|
|
116281
116886
|
const c = getServiceController(instanceId);
|
|
116282
116887
|
if (!c) {
|
|
@@ -116303,8 +116908,8 @@ var isAlive = (pid) => {
|
|
|
116303
116908
|
function runningDaemonInfo() {
|
|
116304
116909
|
const lock = join86(daemonDir2(), "daemon.lock");
|
|
116305
116910
|
try {
|
|
116306
|
-
if (!
|
|
116307
|
-
const pid = Number(
|
|
116911
|
+
if (!existsSync48(lock)) return null;
|
|
116912
|
+
const pid = Number(readFileSync53(lock, "utf-8").trim());
|
|
116308
116913
|
if (!pid || !isAlive(pid)) return null;
|
|
116309
116914
|
return { pid, device: readCredentials()?.deviceId };
|
|
116310
116915
|
} catch {
|
|
@@ -116338,7 +116943,7 @@ async function logs(instanceId, follow) {
|
|
|
116338
116943
|
}
|
|
116339
116944
|
|
|
116340
116945
|
// src/net.ts
|
|
116341
|
-
import { readFileSync as
|
|
116946
|
+
import { readFileSync as readFileSync55 } from "node:fs";
|
|
116342
116947
|
import { randomBytes as randomBytes11 } from "node:crypto";
|
|
116343
116948
|
import { hostname as hostname7 } from "node:os";
|
|
116344
116949
|
import { resolve as resolve14 } from "node:path";
|
|
@@ -116403,7 +117008,7 @@ function readOrDie(label, p) {
|
|
|
116403
117008
|
process.exit(1);
|
|
116404
117009
|
}
|
|
116405
117010
|
try {
|
|
116406
|
-
return new Uint8Array(
|
|
117011
|
+
return new Uint8Array(readFileSync55(resolve14(p)));
|
|
116407
117012
|
} catch (e) {
|
|
116408
117013
|
console.error(`net enroll: could not read --${label} ${p}: ${e instanceof Error ? e.message : e}`);
|
|
116409
117014
|
process.exit(1);
|
|
@@ -116475,6 +117080,9 @@ async function netCommand(rest, flags) {
|
|
|
116475
117080
|
const established = s.established ?? [];
|
|
116476
117081
|
const relayed = s.relayed ?? [];
|
|
116477
117082
|
console.log(`peers: ${s.peers ?? 0} known, ${established.length} with a live session`);
|
|
117083
|
+
if (typeof s.policyEpoch === "number") {
|
|
117084
|
+
console.log(`policy: epoch ${s.policyEpoch}${s.policyEpoch === 0 ? " \u2014 no policy yet, so NO traffic will pass" : ""}`);
|
|
117085
|
+
}
|
|
116478
117086
|
if (relayed.length) {
|
|
116479
117087
|
console.log(`relayed: ${relayed.length} (${relayed.join(", ")}) \u2014 these are NOT direct`);
|
|
116480
117088
|
} else if (established.length) {
|
|
@@ -116954,7 +117562,7 @@ async function netCommand(rest, flags) {
|
|
|
116954
117562
|
function pkgVersion() {
|
|
116955
117563
|
try {
|
|
116956
117564
|
const p = join88(dirname40(fileURLToPath8(import.meta.url)), "..", "package.json");
|
|
116957
|
-
return JSON.parse(
|
|
117565
|
+
return JSON.parse(readFileSync56(p, "utf8")).version ?? "0.0.0";
|
|
116958
117566
|
} catch {
|
|
116959
117567
|
return "0.0.0";
|
|
116960
117568
|
}
|
|
@@ -117200,7 +117808,7 @@ async function captureClaudeSubscription(flags) {
|
|
|
117200
117808
|
});
|
|
117201
117809
|
if (code !== 0) throw new Error(`Claude sign-in did not complete (exit ${code}).`);
|
|
117202
117810
|
const file2 = join88(home, ".credentials.json");
|
|
117203
|
-
if (
|
|
117811
|
+
if (existsSync50(file2)) return readFileSync56(file2, "utf8");
|
|
117204
117812
|
if (process.platform === "darwin") {
|
|
117205
117813
|
const value = execFileSync6("security", [
|
|
117206
117814
|
"find-generic-password",
|
|
@@ -117282,7 +117890,7 @@ async function runnerCommand(rest, flags) {
|
|
|
117282
117890
|
process.exit(1);
|
|
117283
117891
|
}
|
|
117284
117892
|
const oauthFilePath = typeof flags["oauth-file"] === "string" ? resolve15(flags["oauth-file"]) : void 0;
|
|
117285
|
-
const oauthAuthFile = oauthFilePath ?
|
|
117893
|
+
const oauthAuthFile = oauthFilePath ? readFileSync56(oauthFilePath, "utf8") : void 0;
|
|
117286
117894
|
if (oauthAuthFile) {
|
|
117287
117895
|
try {
|
|
117288
117896
|
JSON.parse(oauthAuthFile);
|