omnara 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +390 -53
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -210,7 +210,7 @@ function createSseClient({
|
|
|
210
210
|
...options
|
|
211
211
|
}) {
|
|
212
212
|
let lastEventId;
|
|
213
|
-
const sleep2 = sseSleepFn ?? ((ms) => new Promise((
|
|
213
|
+
const sleep2 = sseSleepFn ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
|
|
214
214
|
const createStream = async function* () {
|
|
215
215
|
let retryDelay = sseDefaultRetryDelay ?? 3e3;
|
|
216
216
|
let attempt = 0;
|
|
@@ -2547,7 +2547,13 @@ var zCreateMachineRequest = z.object({
|
|
|
2547
2547
|
});
|
|
2548
2548
|
var zConnectByoMachineRequest = z.object({
|
|
2549
2549
|
display_name: zResourceName,
|
|
2550
|
-
|
|
2550
|
+
description: z.string().optional(),
|
|
2551
|
+
cwd: z.string().optional(),
|
|
2552
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
2553
|
+
secret_env: z.record(z.string(), zSecretId).optional(),
|
|
2554
|
+
metadata: zMachineMetadata.optional(),
|
|
2555
|
+
project_ids: z.array(zProjectId).max(100).optional(),
|
|
2556
|
+
token_name: zResourceName.optional()
|
|
2551
2557
|
});
|
|
2552
2558
|
var zUpdateMachineRequest = z.object({
|
|
2553
2559
|
cwd: z.string().optional(),
|
|
@@ -3672,7 +3678,6 @@ var zListVisibleMachinesQuery = z.object({
|
|
|
3672
3678
|
cursor: z.string().max(1024).optional()
|
|
3673
3679
|
});
|
|
3674
3680
|
var zListVisibleMachinesResponse2 = zListVisibleMachinesResponse;
|
|
3675
|
-
var zCreateMachineBody = zCreateMachineRequest;
|
|
3676
3681
|
var zCreateMachineHeaders = z.object({
|
|
3677
3682
|
"Idempotency-Key": z.string().min(1).max(255).optional()
|
|
3678
3683
|
});
|
|
@@ -3680,6 +3685,7 @@ var zCreateMachinePath = z.object({
|
|
|
3680
3685
|
orgID: z.string().regex(/^org_[a-z2-7]{26}$/)
|
|
3681
3686
|
});
|
|
3682
3687
|
var zCreateMachineResponse = zMachine;
|
|
3688
|
+
var zConnectByoMachineBody = zConnectByoMachineRequest;
|
|
3683
3689
|
var zConnectByoMachinePath = z.object({
|
|
3684
3690
|
orgID: zOrganizationId
|
|
3685
3691
|
});
|
|
@@ -5693,11 +5699,19 @@ var createMachine = (options) => (options.client ?? client).post({
|
|
|
5693
5699
|
});
|
|
5694
5700
|
var connectByoMachine = (options) => (options.client ?? client).post({
|
|
5695
5701
|
responseValidator: async (data) => await validateResponse(zConnectByoMachineResponse2, data),
|
|
5696
|
-
security: [
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5702
|
+
security: [
|
|
5703
|
+
{
|
|
5704
|
+
key: "bearerAuth",
|
|
5705
|
+
scheme: "bearer",
|
|
5706
|
+
type: "http"
|
|
5707
|
+
},
|
|
5708
|
+
{
|
|
5709
|
+
in: "cookie",
|
|
5710
|
+
name: "__Host-omnara_session",
|
|
5711
|
+
type: "apiKey"
|
|
5712
|
+
},
|
|
5713
|
+
{ name: "X-Omnara-Csrf", type: "apiKey" }
|
|
5714
|
+
],
|
|
5701
5715
|
url: "/api/v1/orgs/{orgID}/machines/connect",
|
|
5702
5716
|
...options,
|
|
5703
5717
|
headers: {
|
|
@@ -6305,10 +6319,10 @@ var getDaemonSkillArchive = (options) => (options.client ?? client).get({
|
|
|
6305
6319
|
|
|
6306
6320
|
// ../sdk/src/auth.ts
|
|
6307
6321
|
function bearerToken(token) {
|
|
6308
|
-
const
|
|
6322
|
+
const resolve3 = typeof token === "function" ? token : () => token;
|
|
6309
6323
|
return {
|
|
6310
6324
|
async authenticate(request) {
|
|
6311
|
-
const value = await
|
|
6325
|
+
const value = await resolve3();
|
|
6312
6326
|
if (value) request.headers.set("Authorization", `Bearer ${value}`);
|
|
6313
6327
|
}
|
|
6314
6328
|
};
|
|
@@ -6456,7 +6470,7 @@ async function startDeviceAuth(options) {
|
|
|
6456
6470
|
};
|
|
6457
6471
|
}
|
|
6458
6472
|
function defaultSleep(seconds) {
|
|
6459
|
-
return new Promise((
|
|
6473
|
+
return new Promise((resolve3) => setTimeout(resolve3, seconds * 1e3));
|
|
6460
6474
|
}
|
|
6461
6475
|
async function pollDeviceAuthToken(options) {
|
|
6462
6476
|
const fetchImpl = options.fetch ?? fetch;
|
|
@@ -7052,6 +7066,7 @@ function flowOp(spec) {
|
|
|
7052
7066
|
type: "flow",
|
|
7053
7067
|
execute: (input) => run({
|
|
7054
7068
|
client: input.client,
|
|
7069
|
+
baseUrl: input.baseUrl,
|
|
7055
7070
|
path: parseWithSchema(spec.path, input.path, "arguments"),
|
|
7056
7071
|
body: parseWithSchema(spec.body, input.body, "flags"),
|
|
7057
7072
|
report: createFlowReporter(spec.summary)
|
|
@@ -7261,7 +7276,7 @@ function registerOperation(parent, config2, spec) {
|
|
|
7261
7276
|
renderResult(data, true);
|
|
7262
7277
|
return;
|
|
7263
7278
|
}
|
|
7264
|
-
const formatted = spec.format(data);
|
|
7279
|
+
const formatted = spec.format(data, { baseUrl: config2.baseUrl });
|
|
7265
7280
|
renderResult(formatted.value, false, { columns: formatted.columns });
|
|
7266
7281
|
});
|
|
7267
7282
|
});
|
|
@@ -7277,6 +7292,7 @@ function registerFlow(parent, config2, spec) {
|
|
|
7277
7292
|
const options = command.opts();
|
|
7278
7293
|
await spec.execute({
|
|
7279
7294
|
client: config2.client,
|
|
7295
|
+
baseUrl: config2.baseUrl,
|
|
7280
7296
|
path: await resolvePathValues(plan, args, options, config2),
|
|
7281
7297
|
body: collectFlagValues(bodyFlags, options)
|
|
7282
7298
|
});
|
|
@@ -7479,7 +7495,7 @@ function registerLoginCommand(program2, cli) {
|
|
|
7479
7495
|
}
|
|
7480
7496
|
|
|
7481
7497
|
// src/manifest.ts
|
|
7482
|
-
import * as
|
|
7498
|
+
import * as z14 from "zod";
|
|
7483
7499
|
|
|
7484
7500
|
// src/config-attachment.ts
|
|
7485
7501
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
@@ -7574,18 +7590,332 @@ function formatVoid(message = "ok") {
|
|
|
7574
7590
|
return () => ({ value: message });
|
|
7575
7591
|
}
|
|
7576
7592
|
|
|
7593
|
+
// src/machine-setup.ts
|
|
7594
|
+
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
7595
|
+
import { accessSync, constants, existsSync as existsSync2, readdirSync, readFileSync as readFileSync3 } from "node:fs";
|
|
7596
|
+
import { homedir as homedir2 } from "node:os";
|
|
7597
|
+
import { basename, dirname as dirname2, isAbsolute, join as join2, resolve } from "node:path";
|
|
7598
|
+
import * as z9 from "zod";
|
|
7599
|
+
var zMachineSetupBody = zConnectByoMachineRequest;
|
|
7600
|
+
async function connectMachine(context) {
|
|
7601
|
+
const { client: client2, path, body, report } = context;
|
|
7602
|
+
report.start("Creating machine with a daemon token");
|
|
7603
|
+
try {
|
|
7604
|
+
const { data } = await sdk_gen_exports.connectByoMachine({ client: client2, path, body });
|
|
7605
|
+
report.stop(`Machine created: ${data.machine.id}`);
|
|
7606
|
+
if (data.project_grants.length > 0) {
|
|
7607
|
+
report.info(`Granted to ${data.project_grants.length} project(s)`);
|
|
7608
|
+
}
|
|
7609
|
+
return data;
|
|
7610
|
+
} catch (error) {
|
|
7611
|
+
report.fail("Machine could not be created");
|
|
7612
|
+
throw error;
|
|
7613
|
+
}
|
|
7614
|
+
}
|
|
7615
|
+
function shellQuote(value) {
|
|
7616
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
7617
|
+
}
|
|
7618
|
+
function installCommand(baseUrl) {
|
|
7619
|
+
return `curl -fsSL ${shellQuote(`${baseUrl}/install/omnarad.sh`)} | sh`;
|
|
7620
|
+
}
|
|
7621
|
+
var formatMachineSetup = (response, { baseUrl }) => ({
|
|
7622
|
+
value: {
|
|
7623
|
+
...response,
|
|
7624
|
+
install_command: installCommand(baseUrl),
|
|
7625
|
+
install_note: "Run install_command on the target machine and paste the token when prompted."
|
|
7626
|
+
}
|
|
7627
|
+
});
|
|
7628
|
+
var daemonConfigFileName = "daemon.json";
|
|
7629
|
+
var installLockFileName = "install.lock";
|
|
7630
|
+
var daemonLockFileName = "daemon.lock";
|
|
7631
|
+
var daemonLockPollMs = 250;
|
|
7632
|
+
var zDaemonConfigFile = z9.looseObject({
|
|
7633
|
+
machine_id: z9.string().optional(),
|
|
7634
|
+
api_url: z9.string().optional()
|
|
7635
|
+
});
|
|
7636
|
+
function daemonHome() {
|
|
7637
|
+
const override = process.env.OMNARA_HOME;
|
|
7638
|
+
if (override !== void 0 && override !== "") {
|
|
7639
|
+
if (!isAbsolute(override) || resolve(override) !== override) {
|
|
7640
|
+
throw new CliInputError("OMNARA_HOME must be an absolute clean path");
|
|
7641
|
+
}
|
|
7642
|
+
if (dirname2(override) === override) {
|
|
7643
|
+
throw new CliInputError("OMNARA_HOME cannot be a filesystem root");
|
|
7644
|
+
}
|
|
7645
|
+
return override;
|
|
7646
|
+
}
|
|
7647
|
+
const userHome = homedir2();
|
|
7648
|
+
if (userHome === "" || !isAbsolute(userHome) || userHome.trim() !== userHome) {
|
|
7649
|
+
throw new CliInputError("HOME must be an absolute path so omnarad can install under ~/.omnarad");
|
|
7650
|
+
}
|
|
7651
|
+
return join2(userHome, ".omnarad");
|
|
7652
|
+
}
|
|
7653
|
+
var supportedPlatforms = /* @__PURE__ */ new Set(["darwin", "linux"]);
|
|
7654
|
+
var supportedArchitectures = /* @__PURE__ */ new Set(["x64", "arm64"]);
|
|
7655
|
+
function ensureSupportedPlatform(platform, architecture) {
|
|
7656
|
+
if (!supportedPlatforms.has(platform)) {
|
|
7657
|
+
throw new CliInputError(`omnarad supports macOS and Linux; this machine reports ${platform}`);
|
|
7658
|
+
}
|
|
7659
|
+
if (!supportedArchitectures.has(architecture)) {
|
|
7660
|
+
throw new CliInputError(
|
|
7661
|
+
`omnarad supports amd64 and arm64; this machine reports ${architecture}`
|
|
7662
|
+
);
|
|
7663
|
+
}
|
|
7664
|
+
}
|
|
7665
|
+
function isLoopbackHost(hostname2) {
|
|
7666
|
+
if (hostname2 === "localhost" || hostname2 === "[::1]" || hostname2 === "::1") return true;
|
|
7667
|
+
const octets = hostname2.split(".");
|
|
7668
|
+
return octets.length === 4 && octets[0] === "127" && octets.every((octet) => /^\d{1,3}$/.test(octet));
|
|
7669
|
+
}
|
|
7670
|
+
function ensureDaemonApiUrl(raw) {
|
|
7671
|
+
const trimmed = raw.trim();
|
|
7672
|
+
let parsed;
|
|
7673
|
+
try {
|
|
7674
|
+
parsed = new URL(trimmed);
|
|
7675
|
+
} catch {
|
|
7676
|
+
throw new CliInputError(`omnarad rejects the API URL ${raw}: it must be an absolute URL`);
|
|
7677
|
+
}
|
|
7678
|
+
const reject = (reason) => {
|
|
7679
|
+
throw new CliInputError(`omnarad rejects the API URL ${raw}: ${reason}`);
|
|
7680
|
+
};
|
|
7681
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
7682
|
+
reject("the scheme must be https or loopback http");
|
|
7683
|
+
}
|
|
7684
|
+
if (parsed.hostname === "") reject("a host is required");
|
|
7685
|
+
if (parsed.username !== "" || parsed.password !== "") reject("it must not contain user info");
|
|
7686
|
+
if (trimmed.includes("?") || trimmed.includes("#")) {
|
|
7687
|
+
reject("it must not contain a query or fragment");
|
|
7688
|
+
}
|
|
7689
|
+
const hostname2 = parsed.hostname.toLowerCase();
|
|
7690
|
+
if (parsed.protocol === "http:" && hostname2 !== "host.docker.internal" && !isLoopbackHost(hostname2)) {
|
|
7691
|
+
reject("it must use https unless the host is local");
|
|
7692
|
+
}
|
|
7693
|
+
}
|
|
7694
|
+
function describeDaemonConfig(configPath) {
|
|
7695
|
+
try {
|
|
7696
|
+
const config2 = zDaemonConfigFile.parse(JSON.parse(readFileSync3(configPath, "utf8")));
|
|
7697
|
+
const details = [
|
|
7698
|
+
...config2.machine_id === void 0 ? [] : [`machine ${config2.machine_id}`],
|
|
7699
|
+
...config2.api_url === void 0 ? [] : [`API ${config2.api_url}`]
|
|
7700
|
+
];
|
|
7701
|
+
return details.length === 0 ? configPath : `${configPath} (${details.join(", ")})`;
|
|
7702
|
+
} catch {
|
|
7703
|
+
return configPath;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
function describeExistingInstallation(home) {
|
|
7707
|
+
const configPath = join2(home, daemonConfigFileName);
|
|
7708
|
+
if (existsSync2(configPath)) return describeDaemonConfig(configPath);
|
|
7709
|
+
if (!existsSync2(home)) return void 0;
|
|
7710
|
+
const leftovers = readdirSync(home).filter((name) => name !== installLockFileName);
|
|
7711
|
+
return leftovers.length === 0 ? void 0 : `${home} already contains ${leftovers.join(", ")}`;
|
|
7712
|
+
}
|
|
7713
|
+
function nearestExistingAncestor(path) {
|
|
7714
|
+
const parent = dirname2(path);
|
|
7715
|
+
return existsSync2(path) || parent === path ? path : nearestExistingAncestor(parent);
|
|
7716
|
+
}
|
|
7717
|
+
function ensureDaemonHomeWritable(home) {
|
|
7718
|
+
const target = nearestExistingAncestor(home);
|
|
7719
|
+
try {
|
|
7720
|
+
accessSync(target, constants.W_OK);
|
|
7721
|
+
} catch {
|
|
7722
|
+
throw new CliInputError(`omnarad cannot be installed because ${target} is not writable`);
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
var DaemonExitError = class extends Error {
|
|
7726
|
+
};
|
|
7727
|
+
async function runMachineCreateLocal(context) {
|
|
7728
|
+
const { report, baseUrl } = context;
|
|
7729
|
+
ensureSupportedPlatform(process.platform, process.arch);
|
|
7730
|
+
ensureDaemonApiUrl(baseUrl);
|
|
7731
|
+
const home = daemonHome();
|
|
7732
|
+
const existing = describeExistingInstallation(home);
|
|
7733
|
+
if (existing !== void 0) {
|
|
7734
|
+
report.warn(`omnarad is already installed on this computer: ${existing}`);
|
|
7735
|
+
report.info(
|
|
7736
|
+
[
|
|
7737
|
+
"Nothing was created. Check the daemon with: omnarad status, or start it with: omnarad restart",
|
|
7738
|
+
"To connect this computer as a new machine, run: omnarad uninstall, then re-run this command"
|
|
7739
|
+
].join("\n")
|
|
7740
|
+
);
|
|
7741
|
+
throw new CliInputError("omnarad is already installed on this machine");
|
|
7742
|
+
}
|
|
7743
|
+
ensureDaemonHomeWritable(home);
|
|
7744
|
+
const { machine, token } = await connectMachine(context);
|
|
7745
|
+
report.info(`Machine ID: ${machine.id}`);
|
|
7746
|
+
report.start("Installing omnarad on this machine");
|
|
7747
|
+
try {
|
|
7748
|
+
await runInstaller(report, baseUrl, token, machine.id, home);
|
|
7749
|
+
} catch (error) {
|
|
7750
|
+
if (error instanceof DaemonExitError) {
|
|
7751
|
+
report.fail("omnarad exited after it was installed");
|
|
7752
|
+
report.info(
|
|
7753
|
+
[
|
|
7754
|
+
`omnarad is installed and registered as machine ${machine.id}; nothing needs to be reinstalled.`,
|
|
7755
|
+
"Check the daemon with: omnarad status, or launch it again with: omnarad start"
|
|
7756
|
+
].join("\n")
|
|
7757
|
+
);
|
|
7758
|
+
throw error;
|
|
7759
|
+
}
|
|
7760
|
+
report.fail("omnarad installation failed");
|
|
7761
|
+
report.info(`Machine daemon token (shown only once):
|
|
7762
|
+
${token}`);
|
|
7763
|
+
report.url(
|
|
7764
|
+
"Finish setup by running this, then paste the machine token when prompted",
|
|
7765
|
+
installCommand(baseUrl)
|
|
7766
|
+
);
|
|
7767
|
+
throw error;
|
|
7768
|
+
}
|
|
7769
|
+
report.done();
|
|
7770
|
+
}
|
|
7771
|
+
function daemonGuidance(machineId) {
|
|
7772
|
+
return [
|
|
7773
|
+
"omnarad is connected to Omnara as this machine.",
|
|
7774
|
+
"Manage the daemon with: omnarad status | stop | restart | uninstall",
|
|
7775
|
+
`Let agents in a project use this machine with: omnara grant machines add --machine-id ${machineId}`,
|
|
7776
|
+
"Learn more: https://docs.omnara.com/machines/connect"
|
|
7777
|
+
].join("\n");
|
|
7778
|
+
}
|
|
7779
|
+
var foregroundGuidance = [
|
|
7780
|
+
"No launchd/systemd user service manager is available, so omnarad is running in the foreground.",
|
|
7781
|
+
"Its logs stream below; press Ctrl-C to stop the daemon, and run omnarad start to launch it again."
|
|
7782
|
+
].join("\n");
|
|
7783
|
+
var serviceManagerCommands = /* @__PURE__ */ new Set(["launchd", "systemd"]);
|
|
7784
|
+
function parentProcess(pid) {
|
|
7785
|
+
if (process.platform === "linux") {
|
|
7786
|
+
try {
|
|
7787
|
+
const stat = readFileSync3(`/proc/${pid}/stat`, "utf8");
|
|
7788
|
+
const fields = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
7789
|
+
const ppid2 = Number(fields[1]);
|
|
7790
|
+
const parentStat = readFileSync3(`/proc/${ppid2}/stat`, "utf8");
|
|
7791
|
+
const command = parentStat.slice(parentStat.indexOf("(") + 1, parentStat.lastIndexOf(")"));
|
|
7792
|
+
return Number.isInteger(ppid2) && ppid2 > 0 ? { pid: ppid2, command } : void 0;
|
|
7793
|
+
} catch {
|
|
7794
|
+
return void 0;
|
|
7795
|
+
}
|
|
7796
|
+
}
|
|
7797
|
+
const result = spawnSync("ps", ["-o", "ppid=", "-p", String(pid)], { encoding: "utf8" });
|
|
7798
|
+
const ppid = Number(result.stdout.trim());
|
|
7799
|
+
if (result.status !== 0 || !Number.isInteger(ppid) || ppid <= 0) return void 0;
|
|
7800
|
+
const parent = spawnSync("ps", ["-o", "comm=", "-p", String(ppid)], { encoding: "utf8" });
|
|
7801
|
+
return { pid: ppid, command: basename(parent.stdout.trim()) };
|
|
7802
|
+
}
|
|
7803
|
+
function classifyDaemonSupervision(daemonPid, installerPid, lookupParent) {
|
|
7804
|
+
let current = daemonPid;
|
|
7805
|
+
for (let depth = 0; depth < 16; depth += 1) {
|
|
7806
|
+
const parent = lookupParent(current);
|
|
7807
|
+
if (parent === void 0) return void 0;
|
|
7808
|
+
if (parent.pid === installerPid) return "foreground";
|
|
7809
|
+
if (parent.pid === 1 || serviceManagerCommands.has(parent.command)) return "service";
|
|
7810
|
+
current = parent.pid;
|
|
7811
|
+
}
|
|
7812
|
+
return void 0;
|
|
7813
|
+
}
|
|
7814
|
+
function readDaemonLockPid(home) {
|
|
7815
|
+
try {
|
|
7816
|
+
const pid = Number(readFileSync3(join2(home, daemonLockFileName), "utf8").trim());
|
|
7817
|
+
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
7818
|
+
} catch {
|
|
7819
|
+
return void 0;
|
|
7820
|
+
}
|
|
7821
|
+
}
|
|
7822
|
+
function installerScript(baseUrl) {
|
|
7823
|
+
return [
|
|
7824
|
+
"installer=$(mktemp)",
|
|
7825
|
+
`trap 'rm -f "$installer"' EXIT`,
|
|
7826
|
+
`curl -qfsSL --connect-timeout 10 -m 60 --max-redirs 5 --max-filesize 1048576 --proto '=http,https' --proto-redir '=https' -o "$installer" ${shellQuote(`${baseUrl}/install/omnarad.sh`)}`,
|
|
7827
|
+
'sh "$installer"'
|
|
7828
|
+
].join(" && ");
|
|
7829
|
+
}
|
|
7830
|
+
function installerFailure(code, signal, log3) {
|
|
7831
|
+
const reason = signal === null ? `exit code ${code}` : `signal ${signal}`;
|
|
7832
|
+
return new Error(`omnarad installer failed (${reason})${log3 === "" ? "" : `
|
|
7833
|
+
${log3}`}`);
|
|
7834
|
+
}
|
|
7835
|
+
function runInstaller(report, baseUrl, token, machineId, home) {
|
|
7836
|
+
return new Promise((resolve3, reject) => {
|
|
7837
|
+
const child = spawn2("/bin/sh", ["-c", installerScript(baseUrl)], {
|
|
7838
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
7839
|
+
env: { ...process.env, OMNARA_API_URL: baseUrl, OMNARA_MACHINE_TOKEN: token }
|
|
7840
|
+
});
|
|
7841
|
+
const relay = (signal) => {
|
|
7842
|
+
child.kill(signal);
|
|
7843
|
+
};
|
|
7844
|
+
process.on("SIGINT", relay);
|
|
7845
|
+
process.on("SIGTERM", relay);
|
|
7846
|
+
const buffered = [];
|
|
7847
|
+
let transcript = "";
|
|
7848
|
+
let supervision;
|
|
7849
|
+
const enterForeground = () => {
|
|
7850
|
+
supervision = "foreground";
|
|
7851
|
+
report.stop("omnarad installed");
|
|
7852
|
+
report.info(daemonGuidance(machineId));
|
|
7853
|
+
report.info(foregroundGuidance);
|
|
7854
|
+
for (const [target, data] of buffered) target.write(data);
|
|
7855
|
+
};
|
|
7856
|
+
const lockWatch = setInterval(() => {
|
|
7857
|
+
if (supervision !== void 0 || child.pid === void 0) return;
|
|
7858
|
+
const daemonPid = readDaemonLockPid(home);
|
|
7859
|
+
if (daemonPid === void 0) return;
|
|
7860
|
+
const detected = classifyDaemonSupervision(daemonPid, child.pid, parentProcess);
|
|
7861
|
+
if (detected === "foreground") enterForeground();
|
|
7862
|
+
else if (detected === "service") supervision = "service";
|
|
7863
|
+
}, daemonLockPollMs);
|
|
7864
|
+
const settle = (outcome) => {
|
|
7865
|
+
clearInterval(lockWatch);
|
|
7866
|
+
process.off("SIGINT", relay);
|
|
7867
|
+
process.off("SIGTERM", relay);
|
|
7868
|
+
outcome();
|
|
7869
|
+
};
|
|
7870
|
+
const consume = (stream) => (chunk) => {
|
|
7871
|
+
if (supervision === "foreground") {
|
|
7872
|
+
stream.write(chunk);
|
|
7873
|
+
return;
|
|
7874
|
+
}
|
|
7875
|
+
buffered.push([stream, chunk]);
|
|
7876
|
+
transcript += chunk.toString();
|
|
7877
|
+
};
|
|
7878
|
+
child.stdout.on("data", consume(process.stdout));
|
|
7879
|
+
child.stderr.on("data", consume(process.stderr));
|
|
7880
|
+
child.on("error", (error) => {
|
|
7881
|
+
settle(() => {
|
|
7882
|
+
reject(new Error(`could not run the omnarad installer: ${error.message}`));
|
|
7883
|
+
});
|
|
7884
|
+
});
|
|
7885
|
+
child.on("close", (code, signal) => {
|
|
7886
|
+
settle(() => {
|
|
7887
|
+
const foreground = supervision === "foreground";
|
|
7888
|
+
if (foreground && (code === 0 || signal === "SIGINT")) {
|
|
7889
|
+
report.info("omnarad stopped");
|
|
7890
|
+
resolve3();
|
|
7891
|
+
} else if (foreground) {
|
|
7892
|
+
const reason = signal === null ? `exit code ${code}` : `signal ${signal}`;
|
|
7893
|
+
reject(new DaemonExitError(`omnarad exited while running in the foreground (${reason})`));
|
|
7894
|
+
} else if (code === 0) {
|
|
7895
|
+
report.stop("omnarad installed and started as a background service");
|
|
7896
|
+
for (const [target, data] of buffered) target.write(data);
|
|
7897
|
+
report.info(daemonGuidance(machineId));
|
|
7898
|
+
resolve3();
|
|
7899
|
+
} else {
|
|
7900
|
+
reject(installerFailure(code, signal, transcript.trim()));
|
|
7901
|
+
}
|
|
7902
|
+
});
|
|
7903
|
+
});
|
|
7904
|
+
});
|
|
7905
|
+
}
|
|
7906
|
+
|
|
7577
7907
|
// src/mcp-add.ts
|
|
7578
7908
|
import { isMap, isScalar as isScalar2, parseDocument } from "yaml";
|
|
7579
|
-
import * as
|
|
7909
|
+
import * as z11 from "zod";
|
|
7580
7910
|
|
|
7581
7911
|
// src/mcp-oauth.ts
|
|
7582
|
-
import * as
|
|
7912
|
+
import * as z10 from "zod";
|
|
7583
7913
|
|
|
7584
7914
|
// src/poll.ts
|
|
7585
7915
|
var POLL_INTERVAL_SECONDS = 2;
|
|
7586
7916
|
var MAX_CONSECUTIVE_POLL_FAILURES = 3;
|
|
7587
7917
|
function sleep(seconds) {
|
|
7588
|
-
return new Promise((
|
|
7918
|
+
return new Promise((resolve3) => setTimeout(resolve3, seconds * 1e3));
|
|
7589
7919
|
}
|
|
7590
7920
|
async function pollUntilDeadline(options) {
|
|
7591
7921
|
const deadline = Date.parse(options.expiresAt);
|
|
@@ -7627,7 +7957,7 @@ async function authorizeMcpOAuthSecret(options) {
|
|
|
7627
7957
|
}
|
|
7628
7958
|
});
|
|
7629
7959
|
}
|
|
7630
|
-
var zBrowserFlag =
|
|
7960
|
+
var zBrowserFlag = z10.boolean().default(true).describe("open the authorization URL in a browser");
|
|
7631
7961
|
function openAuthorizationUrl(report, title, url3, browser) {
|
|
7632
7962
|
report.url(title, url3);
|
|
7633
7963
|
if (browser) {
|
|
@@ -7663,7 +7993,7 @@ async function runMcpOAuth(context) {
|
|
|
7663
7993
|
// src/mcp-add.ts
|
|
7664
7994
|
var SERVER_KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9-]{0,31}$/;
|
|
7665
7995
|
var zMcpAddBody = zMcpoAuthStartRequest.omit({ owner: true, name: true }).extend({
|
|
7666
|
-
server_name:
|
|
7996
|
+
server_name: z11.string().regex(
|
|
7667
7997
|
SERVER_KEY_PATTERN,
|
|
7668
7998
|
"must start with a letter and contain at most 32 letters, digits, or hyphens"
|
|
7669
7999
|
).describe("MCP server key used in the agent config"),
|
|
@@ -7676,7 +8006,7 @@ function targetLabel(target) {
|
|
|
7676
8006
|
function serverEntry(url3, secretId) {
|
|
7677
8007
|
return { url: url3, auth: { type: "oauth", secret_id: secretId } };
|
|
7678
8008
|
}
|
|
7679
|
-
var zJsonRecord =
|
|
8009
|
+
var zJsonRecord = z11.record(z11.string(), z11.json());
|
|
7680
8010
|
function prepareJsonConfig(config2, serverName, mcpUrl) {
|
|
7681
8011
|
let parsedJson;
|
|
7682
8012
|
try {
|
|
@@ -7840,18 +8170,18 @@ function runProfileMcpAdd(context) {
|
|
|
7840
8170
|
}
|
|
7841
8171
|
|
|
7842
8172
|
// src/skill-archive.ts
|
|
7843
|
-
import { readdirSync, readFileSync as
|
|
7844
|
-
import { basename, dirname as
|
|
8173
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
8174
|
+
import { basename as basename2, dirname as dirname3, join as join3, resolve as resolve2 } from "node:path";
|
|
7845
8175
|
import * as tar from "tar";
|
|
7846
|
-
import * as
|
|
7847
|
-
var zCreateSkillCliBody =
|
|
8176
|
+
import * as z12 from "zod";
|
|
8177
|
+
var zCreateSkillCliBody = z12.object({
|
|
7848
8178
|
owner: zSkillOwnerInput,
|
|
7849
|
-
archive:
|
|
8179
|
+
archive: z12.string().min(1).describe("path to a skill directory (packed automatically) or a .zip/.tar.gz archive")
|
|
7850
8180
|
});
|
|
7851
8181
|
var ARCHIVE_SUFFIXES = [".zip", ".tar.gz", ".tgz"];
|
|
7852
8182
|
function assertPackable(dir) {
|
|
7853
|
-
for (const entry of
|
|
7854
|
-
const fullPath =
|
|
8183
|
+
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
8184
|
+
const fullPath = join3(dir, entry.name);
|
|
7855
8185
|
if (entry.isSymbolicLink()) {
|
|
7856
8186
|
throw new CliInputError(`cannot pack ${fullPath}: symlinks are not allowed in skill archives`);
|
|
7857
8187
|
}
|
|
@@ -7860,9 +8190,9 @@ function assertPackable(dir) {
|
|
|
7860
8190
|
}
|
|
7861
8191
|
}
|
|
7862
8192
|
async function packDirectory(dir) {
|
|
7863
|
-
const root =
|
|
8193
|
+
const root = resolve2(dir);
|
|
7864
8194
|
assertPackable(root);
|
|
7865
|
-
const stream = tar.create({ cwd:
|
|
8195
|
+
const stream = tar.create({ cwd: dirname3(root), gzip: true, portable: true }, [basename2(root)]);
|
|
7866
8196
|
const chunks = [];
|
|
7867
8197
|
for await (const chunk of stream) chunks.push(chunk);
|
|
7868
8198
|
return Buffer.concat(chunks);
|
|
@@ -7876,28 +8206,28 @@ async function loadSkillArchive(archivePath) {
|
|
|
7876
8206
|
}
|
|
7877
8207
|
if (isDirectory) {
|
|
7878
8208
|
const buffer = await packDirectory(archivePath);
|
|
7879
|
-
return new File([new Uint8Array(buffer)], `${
|
|
8209
|
+
return new File([new Uint8Array(buffer)], `${basename2(resolve2(archivePath))}.tar.gz`);
|
|
7880
8210
|
}
|
|
7881
|
-
const filename =
|
|
8211
|
+
const filename = basename2(archivePath);
|
|
7882
8212
|
if (!ARCHIVE_SUFFIXES.some((suffix) => filename.toLowerCase().endsWith(suffix))) {
|
|
7883
8213
|
throw new CliInputError(
|
|
7884
8214
|
`archive must be a directory or a ${ARCHIVE_SUFFIXES.join("/")} file: ${archivePath}`
|
|
7885
8215
|
);
|
|
7886
8216
|
}
|
|
7887
|
-
return new File([new Uint8Array(
|
|
8217
|
+
return new File([new Uint8Array(readFileSync4(archivePath))], filename);
|
|
7888
8218
|
}
|
|
7889
8219
|
|
|
7890
8220
|
// src/slack-integration.ts
|
|
7891
|
-
import * as
|
|
7892
|
-
var zSlackBody =
|
|
7893
|
-
app_name:
|
|
7894
|
-
app_configuration_token:
|
|
7895
|
-
icon_filename:
|
|
7896
|
-
icon_data_base64:
|
|
7897
|
-
client_id:
|
|
7898
|
-
client_secret:
|
|
7899
|
-
signing_secret:
|
|
7900
|
-
return_to:
|
|
8221
|
+
import * as z13 from "zod";
|
|
8222
|
+
var zSlackBody = z13.object({
|
|
8223
|
+
app_name: z13.string().optional().describe("name for a new Slack app"),
|
|
8224
|
+
app_configuration_token: z13.string().optional().describe("Slack app configuration token for a new app"),
|
|
8225
|
+
icon_filename: z13.string().optional().describe("filename for the new Slack app icon"),
|
|
8226
|
+
icon_data_base64: z13.string().optional().describe("base64-encoded Slack app icon"),
|
|
8227
|
+
client_id: z13.string().optional().describe("existing Slack app client ID"),
|
|
8228
|
+
client_secret: z13.string().optional().describe("existing Slack app client secret"),
|
|
8229
|
+
signing_secret: z13.string().optional().describe("existing Slack app signing secret"),
|
|
8230
|
+
return_to: z13.string().optional().describe("console-relative path opened after authorization"),
|
|
7901
8231
|
browser: zBrowserFlag
|
|
7902
8232
|
});
|
|
7903
8233
|
function parseRequest(body) {
|
|
@@ -7926,7 +8256,7 @@ function parseRequest(body) {
|
|
|
7926
8256
|
if (!result2.success) {
|
|
7927
8257
|
throw new CliInputError(
|
|
7928
8258
|
`invalid existing Slack app parameters:
|
|
7929
|
-
${
|
|
8259
|
+
${z13.prettifyError(result2.error)}`
|
|
7930
8260
|
);
|
|
7931
8261
|
}
|
|
7932
8262
|
return { kind: "existing-app", body: result2.data };
|
|
@@ -7948,7 +8278,7 @@ ${z12.prettifyError(result2.error)}`
|
|
|
7948
8278
|
if (!result.success) {
|
|
7949
8279
|
throw new CliInputError(
|
|
7950
8280
|
`invalid Slack app parameters:
|
|
7951
|
-
${
|
|
8281
|
+
${z13.prettifyError(result.error)}
|
|
7952
8282
|
Pass --app-name and --app-configuration-token, or existing app credentials.`
|
|
7953
8283
|
);
|
|
7954
8284
|
}
|
|
@@ -8043,7 +8373,7 @@ var commandGroups = [
|
|
|
8043
8373
|
body: zConfigAttachment.extend({
|
|
8044
8374
|
profile: zAgentProfileId.optional(),
|
|
8045
8375
|
name: zAgentName.optional(),
|
|
8046
|
-
message:
|
|
8376
|
+
message: z14.string().optional()
|
|
8047
8377
|
}),
|
|
8048
8378
|
transformBody: async ({ profile, name, message, ...attachment }, { client: client2, path }) => ({
|
|
8049
8379
|
profile,
|
|
@@ -8084,7 +8414,7 @@ var commandGroups = [
|
|
|
8084
8414
|
flowOp({
|
|
8085
8415
|
verb: "mcp-add",
|
|
8086
8416
|
summary: "Create an OAuth secret and add an MCP server to an agent",
|
|
8087
|
-
path:
|
|
8417
|
+
path: z14.object({
|
|
8088
8418
|
orgID: zOrganizationId,
|
|
8089
8419
|
projectID: zProjectId,
|
|
8090
8420
|
agentID: zAgentId
|
|
@@ -8329,11 +8659,18 @@ var commandGroups = [
|
|
|
8329
8659
|
}),
|
|
8330
8660
|
op({
|
|
8331
8661
|
verb: "create",
|
|
8332
|
-
summary: "Create a machine",
|
|
8333
|
-
fn: sdk_gen_exports.
|
|
8334
|
-
format:
|
|
8335
|
-
path:
|
|
8336
|
-
body:
|
|
8662
|
+
summary: "Create a machine with a daemon token and show how to install omnarad",
|
|
8663
|
+
fn: sdk_gen_exports.connectByoMachine,
|
|
8664
|
+
format: formatMachineSetup,
|
|
8665
|
+
path: zConnectByoMachinePath,
|
|
8666
|
+
body: zConnectByoMachineBody
|
|
8667
|
+
}),
|
|
8668
|
+
flowOp({
|
|
8669
|
+
verb: "create-local",
|
|
8670
|
+
summary: "Create a machine and install omnarad on this machine",
|
|
8671
|
+
path: zConnectByoMachinePath,
|
|
8672
|
+
body: zMachineSetupBody,
|
|
8673
|
+
run: runMachineCreateLocal
|
|
8337
8674
|
}),
|
|
8338
8675
|
op({
|
|
8339
8676
|
verb: "update",
|
|
@@ -8546,7 +8883,7 @@ var commandGroups = [
|
|
|
8546
8883
|
flowOp({
|
|
8547
8884
|
verb: "mcp-oauth",
|
|
8548
8885
|
summary: "Create a secret through an MCP server OAuth flow",
|
|
8549
|
-
path:
|
|
8886
|
+
path: z14.object({ orgID: zOrganizationId }),
|
|
8550
8887
|
body: zMcpOAuthBody,
|
|
8551
8888
|
run: runMcpOAuth
|
|
8552
8889
|
})
|
|
@@ -8660,7 +8997,7 @@ var commandGroups = [
|
|
|
8660
8997
|
flowOp({
|
|
8661
8998
|
verb: "mcp-add",
|
|
8662
8999
|
summary: "Create an OAuth secret and add an MCP server to an agent profile",
|
|
8663
|
-
path:
|
|
9000
|
+
path: z14.object({
|
|
8664
9001
|
orgID: zOrganizationId,
|
|
8665
9002
|
projectID: zProjectId,
|
|
8666
9003
|
agentProfileID: zAgentProfileId
|
|
@@ -8672,7 +9009,7 @@ var commandGroups = [
|
|
|
8672
9009
|
verb: "slack",
|
|
8673
9010
|
aliases: ["slack-setup"],
|
|
8674
9011
|
summary: "Connect Slack to an agent profile through OAuth",
|
|
8675
|
-
path:
|
|
9012
|
+
path: z14.object({
|
|
8676
9013
|
orgID: zOrganizationId,
|
|
8677
9014
|
projectID: zProjectId,
|
|
8678
9015
|
agentProfileID: zAgentProfileId
|
package/package.json
CHANGED