dahrk-node 0.1.6 → 0.1.8
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/main.js +247 -39
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/main.ts
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
5
|
+
import { existsSync as existsSync7, realpathSync as realpathSync3 } from "fs";
|
|
5
6
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6
|
-
import { homedir as
|
|
7
|
-
import { basename, join as
|
|
7
|
+
import { homedir as homedir5, platform as osPlatform4 } from "os";
|
|
8
|
+
import { basename, join as join10 } from "path";
|
|
8
9
|
import { pathToFileURL } from "url";
|
|
9
10
|
|
|
10
11
|
// ../../packages/edge/src/ws-client.ts
|
|
@@ -640,7 +641,7 @@ function createClaudeRunner() {
|
|
|
640
641
|
maxTurns: MAX_TURNS,
|
|
641
642
|
includePartialMessages: false
|
|
642
643
|
};
|
|
643
|
-
const exit = ctx.config.exit ?? "
|
|
644
|
+
const exit = ctx.config.exit ?? "either";
|
|
644
645
|
const wantsTool = exit === "tool" || exit === "either";
|
|
645
646
|
const mailbox = new ManagedMailbox();
|
|
646
647
|
const q = query({ prompt: mailbox, options });
|
|
@@ -914,7 +915,7 @@ function createCodexRunner() {
|
|
|
914
915
|
async runInteractive(ctx, turns, onTrace) {
|
|
915
916
|
const emit = makeEmit("codex", onTrace);
|
|
916
917
|
const t = openThread(ctx);
|
|
917
|
-
const exit = ctx.config.exit ?? "
|
|
918
|
+
const exit = ctx.config.exit ?? "either";
|
|
918
919
|
if (exit === "tool" || exit === "either") {
|
|
919
920
|
process.stderr.write("codex-adapter: interactive tool-exit not supported in M4; using gate exit\n");
|
|
920
921
|
}
|
|
@@ -1163,7 +1164,7 @@ function createPiRunner(deps = {}) {
|
|
|
1163
1164
|
const emit = makeEmit("pi", onTrace);
|
|
1164
1165
|
const s = await openSession(ctx);
|
|
1165
1166
|
const state = newPiBufferState();
|
|
1166
|
-
const exit = ctx.config.exit ?? "
|
|
1167
|
+
const exit = ctx.config.exit ?? "either";
|
|
1167
1168
|
const wantsTool = exit === "tool" || exit === "either";
|
|
1168
1169
|
let toolFired = false;
|
|
1169
1170
|
let toolSummary = null;
|
|
@@ -2720,6 +2721,15 @@ async function startEdgeNode(opts) {
|
|
|
2720
2721
|
startHeartbeat(ws, msg.heartbeatMs);
|
|
2721
2722
|
}
|
|
2722
2723
|
log(`EDGE_WELCOMED:${msg.name} tenant=${msg.tenantId} credentialMode=${msg.credentialMode}`);
|
|
2724
|
+
try {
|
|
2725
|
+
opts.onEnrolled?.({
|
|
2726
|
+
name: msg.name,
|
|
2727
|
+
tenantId: msg.tenantId,
|
|
2728
|
+
credentialMode: msg.credentialMode
|
|
2729
|
+
});
|
|
2730
|
+
} catch (e) {
|
|
2731
|
+
log(`EDGE_ENROL_PERSIST_FAILED ${e.message}`);
|
|
2732
|
+
}
|
|
2723
2733
|
return;
|
|
2724
2734
|
}
|
|
2725
2735
|
if (msg.type === "blob-put-url") {
|
|
@@ -3009,7 +3019,7 @@ function probeHub(opts) {
|
|
|
3009
3019
|
|
|
3010
3020
|
// src/cli.ts
|
|
3011
3021
|
import { parseArgs } from "util";
|
|
3012
|
-
var COMMANDS = /* @__PURE__ */ new Set(["start", "run", "service", "doctor", "update"]);
|
|
3022
|
+
var COMMANDS = /* @__PURE__ */ new Set(["start", "run", "service", "doctor", "status", "update"]);
|
|
3013
3023
|
var isCommand = (s) => COMMANDS.has(s);
|
|
3014
3024
|
function parseCli(argv) {
|
|
3015
3025
|
const [first, ...rest] = argv;
|
|
@@ -3145,15 +3155,18 @@ function parseUpdate(flagArgs) {
|
|
|
3145
3155
|
function usage(bin, command) {
|
|
3146
3156
|
if (command === "start") {
|
|
3147
3157
|
return [
|
|
3148
|
-
`Usage: ${bin} start --token <token> [options]`,
|
|
3158
|
+
`Usage: ${bin} start [--token <token>] [options]`,
|
|
3149
3159
|
"",
|
|
3150
3160
|
"Run the edge node: dial the hub over WebSocket and serve Jobs in git worktrees.",
|
|
3151
3161
|
"",
|
|
3162
|
+
"A token is needed only to enrol. Once the hub accepts it, it is cached in ~/.dahrk/node.json and",
|
|
3163
|
+
"every later `start` re-attaches without one. Pass --token again to re-enrol (rotated token, new pool).",
|
|
3164
|
+
"",
|
|
3152
3165
|
"Options:",
|
|
3153
|
-
" --token <token> Enrolment token (
|
|
3166
|
+
" --token <token> Enrolment token (first run only; or set DAHRK_ENROL_TOKEN).",
|
|
3154
3167
|
" --hub-url <url> Hub WebSocket URL (or set DAHRK_HUB_URL).",
|
|
3155
3168
|
" --name <name> Display-name override (else the hub assigns one).",
|
|
3156
|
-
" --ephemeral Do not persist
|
|
3169
|
+
" --ephemeral Do not persist (or read) node id and token; mint a throwaway id (CI / one-shot)."
|
|
3157
3170
|
].join("\n");
|
|
3158
3171
|
}
|
|
3159
3172
|
if (command === "run") {
|
|
@@ -3201,6 +3214,18 @@ function usage(bin, command) {
|
|
|
3201
3214
|
" --hub-url <url> Hub WebSocket URL to reach (or set DAHRK_HUB_URL)."
|
|
3202
3215
|
].join("\n");
|
|
3203
3216
|
}
|
|
3217
|
+
if (command === "status") {
|
|
3218
|
+
return [
|
|
3219
|
+
`Usage: ${bin} status`,
|
|
3220
|
+
"",
|
|
3221
|
+
"Report this node's local state: whether it is enrolled (and as whom), its node id, the runtimes",
|
|
3222
|
+
"it can serve, and whether the always-on service is installed and actually running.",
|
|
3223
|
+
"",
|
|
3224
|
+
"Local only - it dials nothing, so it is instant and works offline. Use `doctor` to check the hub",
|
|
3225
|
+
"is reachable and the token still valid. Exits non-zero only when the service is installed but",
|
|
3226
|
+
"not running, so it works as a health check in a script."
|
|
3227
|
+
].join("\n");
|
|
3228
|
+
}
|
|
3204
3229
|
if (command === "update") {
|
|
3205
3230
|
return [
|
|
3206
3231
|
`Usage: ${bin} update [--check]`,
|
|
@@ -3217,9 +3242,10 @@ function usage(bin, command) {
|
|
|
3217
3242
|
`Usage: ${bin} <command> [options]`,
|
|
3218
3243
|
"",
|
|
3219
3244
|
"Commands:",
|
|
3220
|
-
" start Run the edge node (default). Needs a --token
|
|
3245
|
+
" start Run the edge node (default). Needs a --token to enrol; cached thereafter.",
|
|
3221
3246
|
" run Run a workflow locally (engine-backed), e.g. `run preflight`.",
|
|
3222
3247
|
" service Install/uninstall the node as an always-on service (launchd/systemd).",
|
|
3248
|
+
" status Is this node enrolled, and is the service running? (local, dials nothing)",
|
|
3223
3249
|
" doctor Preflight checks: Node, runtimes, hub reachability, token validity.",
|
|
3224
3250
|
" update Update the client to the latest release (or print how for your channel).",
|
|
3225
3251
|
" version Print the client version.",
|
|
@@ -3578,9 +3604,10 @@ function gatherHostFacts(repoPath) {
|
|
|
3578
3604
|
|
|
3579
3605
|
// src/service.ts
|
|
3580
3606
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
3581
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync6, realpathSync, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
3607
|
+
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync6, realpathSync, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
3582
3608
|
import { homedir as homedir3, platform as osPlatform3, userInfo } from "os";
|
|
3583
3609
|
import { join as join8 } from "path";
|
|
3610
|
+
var UNIT_FILE_MODE = 384;
|
|
3584
3611
|
var LAUNCHD_LABEL = "ai.dahrk.node";
|
|
3585
3612
|
var SYSTEMD_UNIT = "dahrk-node.service";
|
|
3586
3613
|
function detectManager(plat) {
|
|
@@ -3699,6 +3726,24 @@ function buildPlan(inputs) {
|
|
|
3699
3726
|
logHint: `journalctl --user -u ${SYSTEMD_UNIT} -f`
|
|
3700
3727
|
};
|
|
3701
3728
|
}
|
|
3729
|
+
function unitPath(manager, homeDir) {
|
|
3730
|
+
return manager === "launchd" ? join8(homeDir, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`) : join8(homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
3731
|
+
}
|
|
3732
|
+
function statusCommand(manager) {
|
|
3733
|
+
return manager === "launchd" ? ["launchctl", "list", LAUNCHD_LABEL] : ["systemctl", "--user", "show", SYSTEMD_UNIT, "-p", "ActiveState", "-p", "MainPID"];
|
|
3734
|
+
}
|
|
3735
|
+
function parseServiceStatus(manager, unitExists, probe2) {
|
|
3736
|
+
if (!unitExists) return { installed: false, running: false };
|
|
3737
|
+
if (probe2.code !== 0) return { installed: true, running: false };
|
|
3738
|
+
if (manager === "launchd") {
|
|
3739
|
+
const pid2 = Number(/"PID"\s*=\s*(\d+);/.exec(probe2.stdout)?.[1]);
|
|
3740
|
+
return pid2 > 0 ? { installed: true, running: true, pid: pid2 } : { installed: true, running: false };
|
|
3741
|
+
}
|
|
3742
|
+
const active = /^ActiveState=(.*)$/m.exec(probe2.stdout)?.[1]?.trim();
|
|
3743
|
+
const pid = Number(/^MainPID=(\d+)$/m.exec(probe2.stdout)?.[1]);
|
|
3744
|
+
const running = active === "active";
|
|
3745
|
+
return running && pid > 0 ? { installed: true, running: true, pid } : { installed: true, running };
|
|
3746
|
+
}
|
|
3702
3747
|
function printUnsupported(out) {
|
|
3703
3748
|
out("dahrk service is supported on macOS (launchd) and Linux (systemd) only.");
|
|
3704
3749
|
out("On other platforms, run the node under a process manager such as pm2 (see the README).");
|
|
@@ -3797,17 +3842,39 @@ function resolveScriptPath() {
|
|
|
3797
3842
|
return argv1;
|
|
3798
3843
|
}
|
|
3799
3844
|
}
|
|
3845
|
+
function stableNodeBin(execPath, realpath) {
|
|
3846
|
+
const m = /^(?<prefix>.*)\/Cellar\/(?<formula>node(?:@[\d.]+)?)\/[^/]+\/bin\/node$/.exec(execPath);
|
|
3847
|
+
const { prefix, formula } = m?.groups ?? {};
|
|
3848
|
+
if (!prefix || !formula) return execPath;
|
|
3849
|
+
const candidates = [`${prefix}/opt/${formula}/bin/node`, `${prefix}/bin/node`];
|
|
3850
|
+
return candidates.find((c) => realpath(c) === execPath) ?? execPath;
|
|
3851
|
+
}
|
|
3852
|
+
var realpathOrUndefined = (p) => {
|
|
3853
|
+
try {
|
|
3854
|
+
return realpathSync(p);
|
|
3855
|
+
} catch {
|
|
3856
|
+
return void 0;
|
|
3857
|
+
}
|
|
3858
|
+
};
|
|
3800
3859
|
var defaultDeps3 = () => ({
|
|
3801
3860
|
platform: osPlatform3(),
|
|
3802
3861
|
homeDir: homedir3(),
|
|
3803
|
-
|
|
3862
|
+
// Not `process.execPath` raw: that is the versioned Homebrew Cellar path, which the next
|
|
3863
|
+
// `brew upgrade node` deletes out from under the unit. See `stableNodeBin`.
|
|
3864
|
+
nodeBin: stableNodeBin(process.execPath, realpathOrUndefined),
|
|
3804
3865
|
scriptPath: resolveScriptPath(),
|
|
3805
3866
|
logDir: join8(process.env.DAHRK_STATE_DIR ?? join8(homedir3(), ".dahrk"), "logs"),
|
|
3806
3867
|
// Snapshot the operator's PATH at install time so the daemon finds git + the runtime CLIs (Homebrew /
|
|
3807
3868
|
// npm-global bins) that a supervisor's minimal PATH would otherwise hide.
|
|
3808
3869
|
pathEnv: process.env.PATH,
|
|
3809
3870
|
mkdirp: (dir) => void mkdirSync6(dir, { recursive: true }),
|
|
3810
|
-
|
|
3871
|
+
// The unit's environment block carries the enrolment token, so the file is a secret: write it
|
|
3872
|
+
// owner-only. `writeFileSync`'s `mode` applies only when it CREATES the file, so chmod explicitly
|
|
3873
|
+
// too - re-installing over a unit an older client left at 0644 must tighten it, not keep it.
|
|
3874
|
+
writeFile: (path, content) => {
|
|
3875
|
+
writeFileSync6(path, content, { mode: UNIT_FILE_MODE });
|
|
3876
|
+
chmodSync(path, UNIT_FILE_MODE);
|
|
3877
|
+
},
|
|
3811
3878
|
removeFile: (path) => rmSync4(path, { force: true }),
|
|
3812
3879
|
fileExists: (path) => existsSync5(path),
|
|
3813
3880
|
run: (argv) => {
|
|
@@ -3947,47 +4014,149 @@ var defaultDeps4 = () => ({
|
|
|
3947
4014
|
`)
|
|
3948
4015
|
});
|
|
3949
4016
|
|
|
3950
|
-
// src/
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
var
|
|
3955
|
-
var
|
|
4017
|
+
// src/state.ts
|
|
4018
|
+
import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
4019
|
+
import { homedir as homedir4 } from "os";
|
|
4020
|
+
import { join as join9 } from "path";
|
|
4021
|
+
var STRING_FIELDS = ["nodeId", "enrolToken", "name", "tenantId"];
|
|
4022
|
+
var FILE_MODE = 384;
|
|
4023
|
+
var DIR_MODE = 448;
|
|
3956
4024
|
function stateDir(env) {
|
|
3957
4025
|
return env.DAHRK_STATE_DIR ?? join9(homedir4(), ".dahrk");
|
|
3958
4026
|
}
|
|
3959
4027
|
function legacyStateDir(env) {
|
|
3960
4028
|
return env.DAHRK_STATE_DIR ? void 0 : join9(homedir4(), ".skakel");
|
|
3961
4029
|
}
|
|
3962
|
-
function
|
|
3963
|
-
|
|
4030
|
+
function stateFile(env) {
|
|
4031
|
+
return join9(stateDir(env), "node.json");
|
|
4032
|
+
}
|
|
4033
|
+
function readState(file) {
|
|
4034
|
+
if (!existsSync6(file)) return {};
|
|
3964
4035
|
try {
|
|
3965
4036
|
const parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
3966
|
-
|
|
4037
|
+
const state = {};
|
|
4038
|
+
for (const key of STRING_FIELDS) {
|
|
4039
|
+
const value = parsed[key];
|
|
4040
|
+
if (typeof value === "string" && value) state[key] = value;
|
|
4041
|
+
}
|
|
4042
|
+
return state;
|
|
3967
4043
|
} catch {
|
|
4044
|
+
return {};
|
|
3968
4045
|
}
|
|
3969
|
-
return void 0;
|
|
3970
4046
|
}
|
|
4047
|
+
function writeState(env, patch) {
|
|
4048
|
+
const dir = stateDir(env);
|
|
4049
|
+
const file = stateFile(env);
|
|
4050
|
+
try {
|
|
4051
|
+
mkdirSync7(dir, { recursive: true, mode: DIR_MODE });
|
|
4052
|
+
const next = { ...readState(file), ...patch };
|
|
4053
|
+
writeFileSync7(file, `${JSON.stringify(next, null, 2)}
|
|
4054
|
+
`, { mode: FILE_MODE });
|
|
4055
|
+
chmodSync2(file, FILE_MODE);
|
|
4056
|
+
} catch (e) {
|
|
4057
|
+
console.warn(`could not persist node state to ${file}: ${e.message}`);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
function readPersistedToken(env) {
|
|
4061
|
+
return readState(stateFile(env)).enrolToken;
|
|
4062
|
+
}
|
|
4063
|
+
function persistEnrolment(env, enrolment) {
|
|
4064
|
+
const { token, name, tenantId } = enrolment;
|
|
4065
|
+
if (!token) return;
|
|
4066
|
+
const current = readState(stateFile(env));
|
|
4067
|
+
const unchanged = current.enrolToken === token && (name === void 0 || current.name === name) && (tenantId === void 0 || current.tenantId === tenantId);
|
|
4068
|
+
if (unchanged) return;
|
|
4069
|
+
writeState(env, {
|
|
4070
|
+
enrolToken: token,
|
|
4071
|
+
...name ? { name } : {},
|
|
4072
|
+
...tenantId ? { tenantId } : {}
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
function resolveEnrolToken(env, opts = {}) {
|
|
4076
|
+
if (env.DAHRK_ENROL_TOKEN) return env.DAHRK_ENROL_TOKEN;
|
|
4077
|
+
if (opts.ephemeral) return void 0;
|
|
4078
|
+
return readPersistedToken(env);
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
// src/status.ts
|
|
4082
|
+
var bullet = (label, value) => ` ${label.padEnd(12)}${value}`;
|
|
4083
|
+
function renderStatus(f) {
|
|
4084
|
+
const lines = ["dahrk status", ""];
|
|
4085
|
+
const { nodeId, name, tenantId, enrolToken } = f.state;
|
|
4086
|
+
if (enrolToken) {
|
|
4087
|
+
lines.push(bullet("Enrolled", name ? `yes, as ${name}` : "yes"));
|
|
4088
|
+
if (tenantId) lines.push(bullet("Tenant", tenantId));
|
|
4089
|
+
} else if (f.envToken) {
|
|
4090
|
+
lines.push(bullet("Enrolled", "yes, via DAHRK_ENROL_TOKEN (caches on the next successful start)"));
|
|
4091
|
+
} else {
|
|
4092
|
+
lines.push(bullet("Enrolled", "no - run `dahrk start --token <token>` once to enrol"));
|
|
4093
|
+
}
|
|
4094
|
+
lines.push(bullet("Node id", nodeId ?? "not yet minted (first `dahrk start` mints one)"));
|
|
4095
|
+
lines.push(bullet("Client", f.clientVersion));
|
|
4096
|
+
lines.push(bullet("Hub", f.hubUrl));
|
|
4097
|
+
lines.push(
|
|
4098
|
+
bullet(
|
|
4099
|
+
"Runtimes",
|
|
4100
|
+
f.runtimes.length > 0 ? f.runtimes.join(", ") : "none detected - this node will serve no Jobs (install claude / codex / pi)"
|
|
4101
|
+
)
|
|
4102
|
+
);
|
|
4103
|
+
if (!f.service) {
|
|
4104
|
+
lines.push(bullet("Service", "not supported on this host (run `dahrk start` under pm2 instead)"));
|
|
4105
|
+
} else if (!f.service.installed) {
|
|
4106
|
+
lines.push(bullet("Service", "not installed - run `dahrk service install` to run on boot"));
|
|
4107
|
+
} else if (f.service.running) {
|
|
4108
|
+
const pid = f.service.pid ? ` (pid ${f.service.pid})` : "";
|
|
4109
|
+
lines.push(bullet("Service", `running${pid}`));
|
|
4110
|
+
} else {
|
|
4111
|
+
lines.push(bullet("Service", "INSTALLED BUT NOT RUNNING - it is failing to start or crash-looping"));
|
|
4112
|
+
if (f.logHint) lines.push(bullet("", `check the logs: ${f.logHint}`));
|
|
4113
|
+
}
|
|
4114
|
+
lines.push("", `State file: ${f.stateFile}`);
|
|
4115
|
+
return lines;
|
|
4116
|
+
}
|
|
4117
|
+
async function runStatus(inputs, deps) {
|
|
4118
|
+
const manager = detectManager(deps.platform);
|
|
4119
|
+
let service;
|
|
4120
|
+
let logHint;
|
|
4121
|
+
if (manager !== "unsupported") {
|
|
4122
|
+
const unit = unitPath(manager, deps.homeDir);
|
|
4123
|
+
const exists = deps.fileExists(unit);
|
|
4124
|
+
const probe2 = exists ? deps.capture(statusCommand(manager)) : { code: 1, stdout: "" };
|
|
4125
|
+
service = parseServiceStatus(manager, exists, probe2);
|
|
4126
|
+
logHint = manager === "launchd" ? `tail -f ${deps.homeDir}/.dahrk/logs/node.err.log` : "journalctl --user -u dahrk-node.service -f";
|
|
4127
|
+
}
|
|
4128
|
+
const facts = {
|
|
4129
|
+
clientVersion: inputs.clientVersion,
|
|
4130
|
+
hubUrl: inputs.hubUrl,
|
|
4131
|
+
stateFile: stateFile(deps.env),
|
|
4132
|
+
state: readState(stateFile(deps.env)),
|
|
4133
|
+
envToken: Boolean(deps.env.DAHRK_ENROL_TOKEN),
|
|
4134
|
+
runtimes: await deps.detectRuntimes(),
|
|
4135
|
+
...service ? { service } : {},
|
|
4136
|
+
...logHint ? { logHint } : {}
|
|
4137
|
+
};
|
|
4138
|
+
for (const line of renderStatus(facts)) deps.out(line);
|
|
4139
|
+
return service?.installed && !service.running ? 1 : 0;
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
// src/main.ts
|
|
4143
|
+
var CLIENT_VERSION = "0.1.8";
|
|
4144
|
+
var DEFAULT_HUB_URL = "wss://api.dahrk.ai";
|
|
4145
|
+
var list = (v) => (v ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
4146
|
+
var RUNTIMES = ["claude-code", "codex", "pi"];
|
|
4147
|
+
var isRuntime = (r) => RUNTIMES.includes(r);
|
|
3971
4148
|
function resolveNodeId(env, opts = {}) {
|
|
3972
4149
|
if (env.DAHRK_NODE_ID) return env.DAHRK_NODE_ID;
|
|
3973
4150
|
if (opts.ephemeral) return randomUUID3();
|
|
3974
|
-
const
|
|
3975
|
-
const file = join9(dir, "node.json");
|
|
3976
|
-
const existing = readNodeId(file);
|
|
4151
|
+
const existing = readState(stateFile(env)).nodeId;
|
|
3977
4152
|
if (existing) return existing;
|
|
3978
4153
|
const legacy = legacyStateDir(env);
|
|
3979
4154
|
if (legacy) {
|
|
3980
|
-
const legacyId =
|
|
4155
|
+
const legacyId = readState(join10(legacy, "node.json")).nodeId;
|
|
3981
4156
|
if (legacyId) return legacyId;
|
|
3982
4157
|
}
|
|
3983
4158
|
const nodeId = randomUUID3();
|
|
3984
|
-
|
|
3985
|
-
mkdirSync7(dir, { recursive: true });
|
|
3986
|
-
writeFileSync7(file, `${JSON.stringify({ nodeId }, null, 2)}
|
|
3987
|
-
`);
|
|
3988
|
-
} catch (e) {
|
|
3989
|
-
console.warn(`could not persist node id to ${file}: ${e.message}`);
|
|
3990
|
-
}
|
|
4159
|
+
writeState(env, { nodeId });
|
|
3991
4160
|
return nodeId;
|
|
3992
4161
|
}
|
|
3993
4162
|
async function resolveRuntimes(env) {
|
|
@@ -4053,6 +4222,8 @@ function envWithFlags(env, flags) {
|
|
|
4053
4222
|
async function start(flags) {
|
|
4054
4223
|
const env = envWithFlags(process.env, flags);
|
|
4055
4224
|
const nodeId = resolveNodeId(env, { ephemeral: flags.ephemeral });
|
|
4225
|
+
const token = resolveEnrolToken(env, { ephemeral: flags.ephemeral });
|
|
4226
|
+
if (token) env.DAHRK_ENROL_TOKEN = token;
|
|
4056
4227
|
const runtimes = await resolveRuntimes(env);
|
|
4057
4228
|
if (runtimes.length === 0) {
|
|
4058
4229
|
console.warn(
|
|
@@ -4060,7 +4231,34 @@ async function start(flags) {
|
|
|
4060
4231
|
);
|
|
4061
4232
|
}
|
|
4062
4233
|
const resolved = { nodeId, runtimes, clientVersion: CLIENT_VERSION };
|
|
4063
|
-
|
|
4234
|
+
const persist = token !== void 0 && !flags.ephemeral;
|
|
4235
|
+
await startEdgeNode({
|
|
4236
|
+
...buildEdgeOptions(env, resolved),
|
|
4237
|
+
...persist ? {
|
|
4238
|
+
onEnrolled: (welcome) => persistEnrolment(env, { token, name: welcome.name, tenantId: welcome.tenantId })
|
|
4239
|
+
} : {}
|
|
4240
|
+
});
|
|
4241
|
+
}
|
|
4242
|
+
function statusDeps(env) {
|
|
4243
|
+
return {
|
|
4244
|
+
platform: osPlatform4(),
|
|
4245
|
+
homeDir: homedir5(),
|
|
4246
|
+
env,
|
|
4247
|
+
detectRuntimes: () => resolveRuntimes(env),
|
|
4248
|
+
fileExists: (path) => existsSync7(path),
|
|
4249
|
+
capture: (argv) => {
|
|
4250
|
+
const [cmd, ...args] = argv;
|
|
4251
|
+
try {
|
|
4252
|
+
const stdout = execFileSync7(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
4253
|
+
return { code: 0, stdout };
|
|
4254
|
+
} catch (e) {
|
|
4255
|
+
const status = e.status;
|
|
4256
|
+
return { code: typeof status === "number" ? status : 1, stdout: "" };
|
|
4257
|
+
}
|
|
4258
|
+
},
|
|
4259
|
+
out: (line) => void process.stdout.write(`${line}
|
|
4260
|
+
`)
|
|
4261
|
+
};
|
|
4064
4262
|
}
|
|
4065
4263
|
var KNOWN_WORKFLOWS = ["preflight"];
|
|
4066
4264
|
async function runWorkflow(flags) {
|
|
@@ -4072,7 +4270,7 @@ async function runWorkflow(flags) {
|
|
|
4072
4270
|
}
|
|
4073
4271
|
const env = applyEnvAliases(process.env);
|
|
4074
4272
|
const hubUrl = flags.hubUrl ?? env.DAHRK_HUB_URL;
|
|
4075
|
-
const token = flags.token ?? env
|
|
4273
|
+
const token = flags.token ?? resolveEnrolToken(env);
|
|
4076
4274
|
return runPreflight({
|
|
4077
4275
|
...flags.repo ? { repoPath: flags.repo } : {},
|
|
4078
4276
|
...hubUrl ? { hubUrl } : {},
|
|
@@ -4101,11 +4299,21 @@ async function main() {
|
|
|
4101
4299
|
const env = envWithFlags(process.env, parsed.flags);
|
|
4102
4300
|
process.exitCode = await runDoctor({
|
|
4103
4301
|
hubUrl: env.DAHRK_HUB_URL,
|
|
4104
|
-
token:
|
|
4302
|
+
// Same resolution as `start`, so doctor checks the token the node would actually present:
|
|
4303
|
+
// the flag/env if given, else the one cached by the last successful enrolment.
|
|
4304
|
+
token: resolveEnrolToken(env),
|
|
4105
4305
|
clientVersion: CLIENT_VERSION
|
|
4106
4306
|
});
|
|
4107
4307
|
break;
|
|
4108
4308
|
}
|
|
4309
|
+
case "status": {
|
|
4310
|
+
const env = envWithFlags(process.env, parsed.flags);
|
|
4311
|
+
process.exitCode = await runStatus(
|
|
4312
|
+
{ clientVersion: CLIENT_VERSION, hubUrl: env.DAHRK_HUB_URL ?? DEFAULT_HUB_URL },
|
|
4313
|
+
statusDeps(env)
|
|
4314
|
+
);
|
|
4315
|
+
break;
|
|
4316
|
+
}
|
|
4109
4317
|
case "run":
|
|
4110
4318
|
process.exitCode = await runWorkflow(parsed.flags);
|
|
4111
4319
|
break;
|
|
@@ -4115,7 +4323,7 @@ async function main() {
|
|
|
4115
4323
|
break;
|
|
4116
4324
|
}
|
|
4117
4325
|
const env = applyEnvAliases(process.env);
|
|
4118
|
-
const token = parsed.flags.token ?? env
|
|
4326
|
+
const token = parsed.flags.token ?? resolveEnrolToken(env);
|
|
4119
4327
|
const name = parsed.flags.name ?? env.DAHRK_NODE_NAME;
|
|
4120
4328
|
const hubUrl = parsed.flags.hubUrl ?? env.DAHRK_HUB_URL;
|
|
4121
4329
|
process.exitCode = await runServiceInstall({
|