omnara 1.0.1 → 1.0.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.
Files changed (2) hide show
  1. package/dist/bin.js +570 -56
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -98,6 +98,8 @@ __export(sdk_gen_exports, {
98
98
  listEvents: () => listEvents,
99
99
  listIntegrationInstalls: () => listIntegrationInstalls,
100
100
  listMachinePools: () => listMachinePools,
101
+ listMcpServerTools: () => listMcpServerTools,
102
+ listMcpServers: () => listMcpServers,
101
103
  listMemberProjectAccess: () => listMemberProjectAccess,
102
104
  listModelProviderConfigs: () => listModelProviderConfigs,
103
105
  listOrgApiKeyProjectAccess: () => listOrgApiKeyProjectAccess,
@@ -153,7 +155,8 @@ __export(sdk_gen_exports, {
153
155
  updateOrgMember: () => updateOrgMember,
154
156
  updateProjectMachinePoolGrant: () => updateProjectMachinePoolGrant,
155
157
  updateProjectModelGrant: () => updateProjectModelGrant,
156
- updateSecret: () => updateSecret
158
+ updateSecret: () => updateSecret,
159
+ uploadDaemonArtifact: () => uploadDaemonArtifact
157
160
  });
158
161
 
159
162
  // ../sdk/src/generated/core/bodySerializer.gen.ts
@@ -210,7 +213,7 @@ function createSseClient({
210
213
  ...options
211
214
  }) {
212
215
  let lastEventId;
213
- const sleep2 = sseSleepFn ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
216
+ const sleep2 = sseSleepFn ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
214
217
  const createStream = async function* () {
215
218
  let retryDelay = sseDefaultRetryDelay ?? 3e3;
216
219
  let attempt = 0;
@@ -1467,6 +1470,102 @@ var zToolCatalog = z.object({
1467
1470
  custom_tool_permissions: zToolPermissionProfile,
1468
1471
  mcp_tool_permissions: zToolPermissionProfile
1469
1472
  });
1473
+ var zMcpRegistryHeader = z.object({
1474
+ name: z.string(),
1475
+ description: z.string().optional(),
1476
+ is_required: z.boolean(),
1477
+ is_secret: z.boolean()
1478
+ });
1479
+ var zMcpRegistryRemote = z.object({
1480
+ type: z.string(),
1481
+ url: z.string(),
1482
+ headers: z.array(zMcpRegistryHeader).optional()
1483
+ });
1484
+ var zMcpRegistryIcon = z.object({
1485
+ src: z.string(),
1486
+ mime_type: z.string().optional(),
1487
+ sizes: z.array(z.string()).optional(),
1488
+ theme: z.string().optional()
1489
+ });
1490
+ var zMcpRegistryServer = z.object({
1491
+ name: z.string(),
1492
+ title: z.string().optional(),
1493
+ description: z.string(),
1494
+ version: z.string(),
1495
+ website_url: z.string().optional(),
1496
+ status: z.string(),
1497
+ updated_at: z.iso.datetime({ offset: true }),
1498
+ remotes: z.array(zMcpRegistryRemote),
1499
+ icons: z.array(zMcpRegistryIcon)
1500
+ });
1501
+ var zListMcpServersResponse = z.object({
1502
+ data: z.array(zMcpRegistryServer),
1503
+ next_cursor: z.string().nullable()
1504
+ });
1505
+ var zMcpServerAuthNone = z.object({
1506
+ type: z.enum(["none"])
1507
+ });
1508
+ var zMcpServerAuthBearer = z.object({
1509
+ type: z.enum(["bearer"]),
1510
+ secret_id: zSecretId
1511
+ });
1512
+ var zMcpServerAuthOAuth = z.object({
1513
+ type: z.enum(["oauth"]),
1514
+ secret_id: zSecretId
1515
+ });
1516
+ var zMcpServerAuthSigV4 = z.object({
1517
+ type: z.enum(["sigv4"]),
1518
+ secret_id: zSecretId,
1519
+ service: z.string().min(1).max(64),
1520
+ region: z.string().min(1).max(64)
1521
+ });
1522
+ var zMcpServerAuth = z.discriminatedUnion("type", [
1523
+ zMcpServerAuthNone.extend({ type: z.literal("none") }),
1524
+ zMcpServerAuthBearer.extend({ type: z.literal("bearer") }),
1525
+ zMcpServerAuthOAuth.extend({ type: z.literal("oauth") }),
1526
+ zMcpServerAuthSigV4.extend({ type: z.literal("sigv4") })
1527
+ ]);
1528
+ var zMcpServerToolsRequest = z.object({
1529
+ url: z.url().min(1).max(2048),
1530
+ auth: zMcpServerAuth
1531
+ });
1532
+ var zMcpServerAuthHint = z.object({
1533
+ type: z.enum(["oauth", "bearer"]),
1534
+ scopes: z.array(z.string()).optional(),
1535
+ authorization_server: z.string().optional()
1536
+ });
1537
+ var zMcpServerAuthRequiredError = z.object({
1538
+ error: z.string(),
1539
+ code: z.enum(["unprocessable"]),
1540
+ auth: zMcpServerAuthHint
1541
+ });
1542
+ var zMcpServerInfo = z.object({
1543
+ name: z.string(),
1544
+ version: z.string(),
1545
+ title: z.string().optional(),
1546
+ description: z.string().optional(),
1547
+ website_url: z.string().optional()
1548
+ });
1549
+ var zMcpServerToolAnnotations = z.object({
1550
+ title: z.string().optional(),
1551
+ read_only_hint: z.boolean().optional(),
1552
+ destructive_hint: z.boolean().optional(),
1553
+ idempotent_hint: z.boolean().optional(),
1554
+ open_world_hint: z.boolean().optional()
1555
+ });
1556
+ var zMcpServerTool = z.object({
1557
+ name: z.string(),
1558
+ title: z.string().optional(),
1559
+ description: z.string().optional(),
1560
+ input_schema: z.record(z.string(), z.unknown()),
1561
+ output_schema: z.record(z.string(), z.unknown()).optional(),
1562
+ annotations: zMcpServerToolAnnotations.optional()
1563
+ });
1564
+ var zMcpServerToolsResponse = z.object({
1565
+ protocol_version: z.string(),
1566
+ server_info: zMcpServerInfo,
1567
+ tools: z.array(zMcpServerTool)
1568
+ });
1470
1569
  var zAgentConfigModel = z.object({
1471
1570
  provider_config: zResourceName,
1472
1571
  name: zResourceName,
@@ -1735,6 +1834,7 @@ var zInlineMediaContentBlock = z.object({
1735
1834
  var zMediaRefContentBlock = z.object({
1736
1835
  type: z.enum(["media_ref"]),
1737
1836
  artifact_id: zArtifactId,
1837
+ exclude_from_model_context: z.boolean().optional(),
1738
1838
  metadata: zContentBlockMetadata.optional()
1739
1839
  });
1740
1840
  var zReasoningContentBlock = z.object({
@@ -1777,6 +1877,7 @@ var zAgentInput = z.object({
1777
1877
  delivery_mode: zAgentInputDeliveryMode,
1778
1878
  input_kind: zAgentInputKind,
1779
1879
  actor_id: zActorId.optional(),
1880
+ input_idempotency_key: z.string().optional(),
1780
1881
  content_blocks: z.array(zAgentInputContentBlock).optional(),
1781
1882
  queued_at: zTimestamp
1782
1883
  });
@@ -2547,7 +2648,13 @@ var zCreateMachineRequest = z.object({
2547
2648
  });
2548
2649
  var zConnectByoMachineRequest = z.object({
2549
2650
  display_name: zResourceName,
2550
- project_ids: z.array(zProjectId).max(100)
2651
+ description: z.string().optional(),
2652
+ cwd: z.string().optional(),
2653
+ env: z.record(z.string(), z.string()).optional(),
2654
+ secret_env: z.record(z.string(), zSecretId).optional(),
2655
+ metadata: zMachineMetadata.optional(),
2656
+ project_ids: z.array(zProjectId).max(100).optional(),
2657
+ token_name: zResourceName.optional()
2551
2658
  });
2552
2659
  var zUpdateMachineRequest = z.object({
2553
2660
  cwd: z.string().optional(),
@@ -2820,6 +2927,9 @@ var zBootstrapDaemonResponse = z.object({
2820
2927
  installation_id: zInstallationId,
2821
2928
  machine_id: zMachineId
2822
2929
  });
2930
+ var zUploadArtifactResponse = z.object({
2931
+ artifact_id: zArtifactId
2932
+ });
2823
2933
  var zCreateProjectRequest = z.object({
2824
2934
  name: zResourceName
2825
2935
  });
@@ -3275,6 +3385,18 @@ var zCreateAgentConfigPath = z.object({
3275
3385
  });
3276
3386
  var zCreateAgentConfigResponse = zAgentConfig;
3277
3387
  var zGetToolCatalogResponse = zToolCatalog;
3388
+ var zListMcpServersQuery = z.object({
3389
+ q: z.string().max(200).optional(),
3390
+ remote_url: z.string().max(2048).optional(),
3391
+ limit: z.int().gte(1).lte(100).optional().default(50),
3392
+ cursor: z.string().max(1024).optional()
3393
+ });
3394
+ var zListMcpServersResponse2 = zListMcpServersResponse;
3395
+ var zListMcpServerToolsPath = z.object({
3396
+ orgID: zOrganizationId,
3397
+ projectID: zProjectId
3398
+ });
3399
+ var zListMcpServerToolsResponse = zMcpServerToolsResponse;
3278
3400
  var zGetAgentConfigPath = z.object({
3279
3401
  orgID: z.string().regex(/^org_[a-z2-7]{26}$/),
3280
3402
  projectID: z.string().regex(/^proj_[a-z2-7]{26}$/),
@@ -3672,7 +3794,6 @@ var zListVisibleMachinesQuery = z.object({
3672
3794
  cursor: z.string().max(1024).optional()
3673
3795
  });
3674
3796
  var zListVisibleMachinesResponse2 = zListVisibleMachinesResponse;
3675
- var zCreateMachineBody = zCreateMachineRequest;
3676
3797
  var zCreateMachineHeaders = z.object({
3677
3798
  "Idempotency-Key": z.string().min(1).max(255).optional()
3678
3799
  });
@@ -3680,6 +3801,7 @@ var zCreateMachinePath = z.object({
3680
3801
  orgID: z.string().regex(/^org_[a-z2-7]{26}$/)
3681
3802
  });
3682
3803
  var zCreateMachineResponse = zMachine;
3804
+ var zConnectByoMachineBody = zConnectByoMachineRequest;
3683
3805
  var zConnectByoMachinePath = z.object({
3684
3806
  orgID: zOrganizationId
3685
3807
  });
@@ -3905,6 +4027,14 @@ var zGetDaemonSkillArchiveQuery = z.object({
3905
4027
  download_token: z.string().length(64)
3906
4028
  });
3907
4029
  var zGetDaemonSkillArchiveResponse = z.string();
4030
+ var zUploadDaemonArtifactBody = z.string();
4031
+ var zUploadDaemonArtifactPath = z.object({
4032
+ toolCallID: zToolCallId
4033
+ });
4034
+ var zUploadDaemonArtifactQuery = z.object({
4035
+ filename: z.string().min(1).max(255)
4036
+ });
4037
+ var zUploadDaemonArtifactResponse = zUploadArtifactResponse;
3908
4038
 
3909
4039
  // ../sdk/src/validate-response.ts
3910
4040
  function valueAt(data, path) {
@@ -4865,6 +4995,42 @@ var getToolCatalog = (options) => (options?.client ?? client).get({
4865
4995
  url: "/api/v1/tool-catalog",
4866
4996
  ...options
4867
4997
  });
4998
+ var listMcpServers = (options) => (options?.client ?? client).get({
4999
+ responseValidator: async (data) => await validateResponse(zListMcpServersResponse2, data),
5000
+ security: [{
5001
+ key: "bearerAuth",
5002
+ scheme: "bearer",
5003
+ type: "http"
5004
+ }, {
5005
+ in: "cookie",
5006
+ name: "__Host-omnara_session",
5007
+ type: "apiKey"
5008
+ }],
5009
+ url: "/api/v1/mcp-servers",
5010
+ ...options
5011
+ });
5012
+ var listMcpServerTools = (options) => (options.client ?? client).post({
5013
+ responseValidator: async (data) => await validateResponse(zListMcpServerToolsResponse, data),
5014
+ security: [
5015
+ {
5016
+ key: "bearerAuth",
5017
+ scheme: "bearer",
5018
+ type: "http"
5019
+ },
5020
+ {
5021
+ in: "cookie",
5022
+ name: "__Host-omnara_session",
5023
+ type: "apiKey"
5024
+ },
5025
+ { name: "X-Omnara-Csrf", type: "apiKey" }
5026
+ ],
5027
+ url: "/api/v1/orgs/{orgID}/projects/{projectID}/mcp-servers/tools",
5028
+ ...options,
5029
+ headers: {
5030
+ "Content-Type": "application/json",
5031
+ ...options.headers
5032
+ }
5033
+ });
4868
5034
  var getAgentConfig = (options) => (options.client ?? client).get({
4869
5035
  responseValidator: async (data) => await validateResponse(zGetAgentConfigResponse, data),
4870
5036
  security: [{
@@ -5693,11 +5859,19 @@ var createMachine = (options) => (options.client ?? client).post({
5693
5859
  });
5694
5860
  var connectByoMachine = (options) => (options.client ?? client).post({
5695
5861
  responseValidator: async (data) => await validateResponse(zConnectByoMachineResponse2, data),
5696
- security: [{
5697
- in: "cookie",
5698
- name: "__Host-omnara_session",
5699
- type: "apiKey"
5700
- }, { name: "X-Omnara-Csrf", type: "apiKey" }],
5862
+ security: [
5863
+ {
5864
+ key: "bearerAuth",
5865
+ scheme: "bearer",
5866
+ type: "http"
5867
+ },
5868
+ {
5869
+ in: "cookie",
5870
+ name: "__Host-omnara_session",
5871
+ type: "apiKey"
5872
+ },
5873
+ { name: "X-Omnara-Csrf", type: "apiKey" }
5874
+ ],
5701
5875
  url: "/api/v1/orgs/{orgID}/machines/connect",
5702
5876
  ...options,
5703
5877
  headers: {
@@ -6302,13 +6476,28 @@ var getDaemonSkillArchive = (options) => (options.client ?? client).get({
6302
6476
  url: "/api/v1/daemon/skills/{skillID}/archive",
6303
6477
  ...options
6304
6478
  });
6479
+ var uploadDaemonArtifact = (options) => (options.client ?? client).post({
6480
+ bodySerializer: null,
6481
+ responseValidator: async (data) => await validateResponse(zUploadDaemonArtifactResponse, data),
6482
+ security: [{
6483
+ key: "machineDaemonAuth",
6484
+ scheme: "bearer",
6485
+ type: "http"
6486
+ }],
6487
+ url: "/api/v1/daemon/tool-calls/{toolCallID}/artifact",
6488
+ ...options,
6489
+ headers: {
6490
+ "Content-Type": "application/octet-stream",
6491
+ ...options.headers
6492
+ }
6493
+ });
6305
6494
 
6306
6495
  // ../sdk/src/auth.ts
6307
6496
  function bearerToken(token) {
6308
- const resolve2 = typeof token === "function" ? token : () => token;
6497
+ const resolve3 = typeof token === "function" ? token : () => token;
6309
6498
  return {
6310
6499
  async authenticate(request) {
6311
- const value = await resolve2();
6500
+ const value = await resolve3();
6312
6501
  if (value) request.headers.set("Authorization", `Bearer ${value}`);
6313
6502
  }
6314
6503
  };
@@ -6318,11 +6507,13 @@ function bearerToken(token) {
6318
6507
  var ApiError = class _ApiError extends Error {
6319
6508
  status;
6320
6509
  code;
6321
- constructor(status, message, code) {
6510
+ body;
6511
+ constructor(status, message, code, body) {
6322
6512
  super(message);
6323
6513
  this.name = "ApiError";
6324
6514
  this.status = status;
6325
6515
  this.code = code;
6516
+ this.body = body;
6326
6517
  }
6327
6518
  static async fromResponse(response) {
6328
6519
  let message = `request failed with status ${response.status}`;
@@ -6341,7 +6532,7 @@ var ApiError = class _ApiError extends Error {
6341
6532
  code = data.code;
6342
6533
  }
6343
6534
  }
6344
- return new _ApiError(response.status, message, code);
6535
+ return new _ApiError(response.status, message, code, data);
6345
6536
  }
6346
6537
  };
6347
6538
 
@@ -6456,7 +6647,7 @@ async function startDeviceAuth(options) {
6456
6647
  };
6457
6648
  }
6458
6649
  function defaultSleep(seconds) {
6459
- return new Promise((resolve2) => setTimeout(resolve2, seconds * 1e3));
6650
+ return new Promise((resolve3) => setTimeout(resolve3, seconds * 1e3));
6460
6651
  }
6461
6652
  async function pollDeviceAuthToken(options) {
6462
6653
  const fetchImpl = options.fetch ?? fetch;
@@ -7052,6 +7243,7 @@ function flowOp(spec) {
7052
7243
  type: "flow",
7053
7244
  execute: (input) => run({
7054
7245
  client: input.client,
7246
+ baseUrl: input.baseUrl,
7055
7247
  path: parseWithSchema(spec.path, input.path, "arguments"),
7056
7248
  body: parseWithSchema(spec.body, input.body, "flags"),
7057
7249
  report: createFlowReporter(spec.summary)
@@ -7261,7 +7453,7 @@ function registerOperation(parent, config2, spec) {
7261
7453
  renderResult(data, true);
7262
7454
  return;
7263
7455
  }
7264
- const formatted = spec.format(data);
7456
+ const formatted = spec.format(data, { baseUrl: config2.baseUrl });
7265
7457
  renderResult(formatted.value, false, { columns: formatted.columns });
7266
7458
  });
7267
7459
  });
@@ -7277,6 +7469,7 @@ function registerFlow(parent, config2, spec) {
7277
7469
  const options = command.opts();
7278
7470
  await spec.execute({
7279
7471
  client: config2.client,
7472
+ baseUrl: config2.baseUrl,
7280
7473
  path: await resolvePathValues(plan, args, options, config2),
7281
7474
  body: collectFlagValues(bodyFlags, options)
7282
7475
  });
@@ -7479,7 +7672,7 @@ function registerLoginCommand(program2, cli) {
7479
7672
  }
7480
7673
 
7481
7674
  // src/manifest.ts
7482
- import * as z13 from "zod";
7675
+ import * as z14 from "zod";
7483
7676
 
7484
7677
  // src/config-attachment.ts
7485
7678
  import { readFileSync as readFileSync2 } from "node:fs";
@@ -7574,18 +7767,332 @@ function formatVoid(message = "ok") {
7574
7767
  return () => ({ value: message });
7575
7768
  }
7576
7769
 
7770
+ // src/machine-setup.ts
7771
+ import { spawn as spawn2, spawnSync } from "node:child_process";
7772
+ import { accessSync, constants, existsSync as existsSync2, readdirSync, readFileSync as readFileSync3 } from "node:fs";
7773
+ import { homedir as homedir2 } from "node:os";
7774
+ import { basename, dirname as dirname2, isAbsolute, join as join2, resolve } from "node:path";
7775
+ import * as z9 from "zod";
7776
+ var zMachineSetupBody = zConnectByoMachineRequest;
7777
+ async function connectMachine(context) {
7778
+ const { client: client2, path, body, report } = context;
7779
+ report.start("Creating machine with a daemon token");
7780
+ try {
7781
+ const { data } = await sdk_gen_exports.connectByoMachine({ client: client2, path, body });
7782
+ report.stop(`Machine created: ${data.machine.id}`);
7783
+ if (data.project_grants.length > 0) {
7784
+ report.info(`Granted to ${data.project_grants.length} project(s)`);
7785
+ }
7786
+ return data;
7787
+ } catch (error) {
7788
+ report.fail("Machine could not be created");
7789
+ throw error;
7790
+ }
7791
+ }
7792
+ function shellQuote(value) {
7793
+ return `'${value.replaceAll("'", `'\\''`)}'`;
7794
+ }
7795
+ function installCommand(baseUrl) {
7796
+ return `curl -fsSL ${shellQuote(`${baseUrl}/install/omnarad.sh`)} | sh`;
7797
+ }
7798
+ var formatMachineSetup = (response, { baseUrl }) => ({
7799
+ value: {
7800
+ ...response,
7801
+ install_command: installCommand(baseUrl),
7802
+ install_note: "Run install_command on the target machine and paste the token when prompted."
7803
+ }
7804
+ });
7805
+ var daemonConfigFileName = "daemon.json";
7806
+ var installLockFileName = "install.lock";
7807
+ var daemonLockFileName = "daemon.lock";
7808
+ var daemonLockPollMs = 250;
7809
+ var zDaemonConfigFile = z9.looseObject({
7810
+ machine_id: z9.string().optional(),
7811
+ api_url: z9.string().optional()
7812
+ });
7813
+ function daemonHome() {
7814
+ const override = process.env.OMNARA_HOME;
7815
+ if (override !== void 0 && override !== "") {
7816
+ if (!isAbsolute(override) || resolve(override) !== override) {
7817
+ throw new CliInputError("OMNARA_HOME must be an absolute clean path");
7818
+ }
7819
+ if (dirname2(override) === override) {
7820
+ throw new CliInputError("OMNARA_HOME cannot be a filesystem root");
7821
+ }
7822
+ return override;
7823
+ }
7824
+ const userHome = homedir2();
7825
+ if (userHome === "" || !isAbsolute(userHome) || userHome.trim() !== userHome) {
7826
+ throw new CliInputError("HOME must be an absolute path so omnarad can install under ~/.omnarad");
7827
+ }
7828
+ return join2(userHome, ".omnarad");
7829
+ }
7830
+ var supportedPlatforms = /* @__PURE__ */ new Set(["darwin", "linux"]);
7831
+ var supportedArchitectures = /* @__PURE__ */ new Set(["x64", "arm64"]);
7832
+ function ensureSupportedPlatform(platform, architecture) {
7833
+ if (!supportedPlatforms.has(platform)) {
7834
+ throw new CliInputError(`omnarad supports macOS and Linux; this machine reports ${platform}`);
7835
+ }
7836
+ if (!supportedArchitectures.has(architecture)) {
7837
+ throw new CliInputError(
7838
+ `omnarad supports amd64 and arm64; this machine reports ${architecture}`
7839
+ );
7840
+ }
7841
+ }
7842
+ function isLoopbackHost(hostname2) {
7843
+ if (hostname2 === "localhost" || hostname2 === "[::1]" || hostname2 === "::1") return true;
7844
+ const octets = hostname2.split(".");
7845
+ return octets.length === 4 && octets[0] === "127" && octets.every((octet) => /^\d{1,3}$/.test(octet));
7846
+ }
7847
+ function ensureDaemonApiUrl(raw) {
7848
+ const trimmed = raw.trim();
7849
+ let parsed;
7850
+ try {
7851
+ parsed = new URL(trimmed);
7852
+ } catch {
7853
+ throw new CliInputError(`omnarad rejects the API URL ${raw}: it must be an absolute URL`);
7854
+ }
7855
+ const reject = (reason) => {
7856
+ throw new CliInputError(`omnarad rejects the API URL ${raw}: ${reason}`);
7857
+ };
7858
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
7859
+ reject("the scheme must be https or loopback http");
7860
+ }
7861
+ if (parsed.hostname === "") reject("a host is required");
7862
+ if (parsed.username !== "" || parsed.password !== "") reject("it must not contain user info");
7863
+ if (trimmed.includes("?") || trimmed.includes("#")) {
7864
+ reject("it must not contain a query or fragment");
7865
+ }
7866
+ const hostname2 = parsed.hostname.toLowerCase();
7867
+ if (parsed.protocol === "http:" && hostname2 !== "host.docker.internal" && !isLoopbackHost(hostname2)) {
7868
+ reject("it must use https unless the host is local");
7869
+ }
7870
+ }
7871
+ function describeDaemonConfig(configPath) {
7872
+ try {
7873
+ const config2 = zDaemonConfigFile.parse(JSON.parse(readFileSync3(configPath, "utf8")));
7874
+ const details = [
7875
+ ...config2.machine_id === void 0 ? [] : [`machine ${config2.machine_id}`],
7876
+ ...config2.api_url === void 0 ? [] : [`API ${config2.api_url}`]
7877
+ ];
7878
+ return details.length === 0 ? configPath : `${configPath} (${details.join(", ")})`;
7879
+ } catch {
7880
+ return configPath;
7881
+ }
7882
+ }
7883
+ function describeExistingInstallation(home) {
7884
+ const configPath = join2(home, daemonConfigFileName);
7885
+ if (existsSync2(configPath)) return describeDaemonConfig(configPath);
7886
+ if (!existsSync2(home)) return void 0;
7887
+ const leftovers = readdirSync(home).filter((name) => name !== installLockFileName);
7888
+ return leftovers.length === 0 ? void 0 : `${home} already contains ${leftovers.join(", ")}`;
7889
+ }
7890
+ function nearestExistingAncestor(path) {
7891
+ const parent = dirname2(path);
7892
+ return existsSync2(path) || parent === path ? path : nearestExistingAncestor(parent);
7893
+ }
7894
+ function ensureDaemonHomeWritable(home) {
7895
+ const target = nearestExistingAncestor(home);
7896
+ try {
7897
+ accessSync(target, constants.W_OK);
7898
+ } catch {
7899
+ throw new CliInputError(`omnarad cannot be installed because ${target} is not writable`);
7900
+ }
7901
+ }
7902
+ var DaemonExitError = class extends Error {
7903
+ };
7904
+ async function runMachineCreateLocal(context) {
7905
+ const { report, baseUrl } = context;
7906
+ ensureSupportedPlatform(process.platform, process.arch);
7907
+ ensureDaemonApiUrl(baseUrl);
7908
+ const home = daemonHome();
7909
+ const existing = describeExistingInstallation(home);
7910
+ if (existing !== void 0) {
7911
+ report.warn(`omnarad is already installed on this computer: ${existing}`);
7912
+ report.info(
7913
+ [
7914
+ "Nothing was created. Check the daemon with: omnarad status, or start it with: omnarad restart",
7915
+ "To connect this computer as a new machine, run: omnarad uninstall, then re-run this command"
7916
+ ].join("\n")
7917
+ );
7918
+ throw new CliInputError("omnarad is already installed on this machine");
7919
+ }
7920
+ ensureDaemonHomeWritable(home);
7921
+ const { machine, token } = await connectMachine(context);
7922
+ report.info(`Machine ID: ${machine.id}`);
7923
+ report.start("Installing omnarad on this machine");
7924
+ try {
7925
+ await runInstaller(report, baseUrl, token, machine.id, home);
7926
+ } catch (error) {
7927
+ if (error instanceof DaemonExitError) {
7928
+ report.fail("omnarad exited after it was installed");
7929
+ report.info(
7930
+ [
7931
+ `omnarad is installed and registered as machine ${machine.id}; nothing needs to be reinstalled.`,
7932
+ "Check the daemon with: omnarad status, or launch it again with: omnarad start"
7933
+ ].join("\n")
7934
+ );
7935
+ throw error;
7936
+ }
7937
+ report.fail("omnarad installation failed");
7938
+ report.info(`Machine daemon token (shown only once):
7939
+ ${token}`);
7940
+ report.url(
7941
+ "Finish setup by running this, then paste the machine token when prompted",
7942
+ installCommand(baseUrl)
7943
+ );
7944
+ throw error;
7945
+ }
7946
+ report.done();
7947
+ }
7948
+ function daemonGuidance(machineId) {
7949
+ return [
7950
+ "omnarad is connected to Omnara as this machine.",
7951
+ "Manage the daemon with: omnarad status | stop | restart | uninstall",
7952
+ `Let agents in a project use this machine with: omnara grant machines add --machine-id ${machineId}`,
7953
+ "Learn more: https://docs.omnara.com/machines/connect"
7954
+ ].join("\n");
7955
+ }
7956
+ var foregroundGuidance = [
7957
+ "No launchd/systemd user service manager is available, so omnarad is running in the foreground.",
7958
+ "Its logs stream below; press Ctrl-C to stop the daemon, and run omnarad start to launch it again."
7959
+ ].join("\n");
7960
+ var serviceManagerCommands = /* @__PURE__ */ new Set(["launchd", "systemd"]);
7961
+ function parentProcess(pid) {
7962
+ if (process.platform === "linux") {
7963
+ try {
7964
+ const stat = readFileSync3(`/proc/${pid}/stat`, "utf8");
7965
+ const fields = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
7966
+ const ppid2 = Number(fields[1]);
7967
+ const parentStat = readFileSync3(`/proc/${ppid2}/stat`, "utf8");
7968
+ const command = parentStat.slice(parentStat.indexOf("(") + 1, parentStat.lastIndexOf(")"));
7969
+ return Number.isInteger(ppid2) && ppid2 > 0 ? { pid: ppid2, command } : void 0;
7970
+ } catch {
7971
+ return void 0;
7972
+ }
7973
+ }
7974
+ const result = spawnSync("ps", ["-o", "ppid=", "-p", String(pid)], { encoding: "utf8" });
7975
+ const ppid = Number(result.stdout.trim());
7976
+ if (result.status !== 0 || !Number.isInteger(ppid) || ppid <= 0) return void 0;
7977
+ const parent = spawnSync("ps", ["-o", "comm=", "-p", String(ppid)], { encoding: "utf8" });
7978
+ return { pid: ppid, command: basename(parent.stdout.trim()) };
7979
+ }
7980
+ function classifyDaemonSupervision(daemonPid, installerPid, lookupParent) {
7981
+ let current = daemonPid;
7982
+ for (let depth = 0; depth < 16; depth += 1) {
7983
+ const parent = lookupParent(current);
7984
+ if (parent === void 0) return void 0;
7985
+ if (parent.pid === installerPid) return "foreground";
7986
+ if (parent.pid === 1 || serviceManagerCommands.has(parent.command)) return "service";
7987
+ current = parent.pid;
7988
+ }
7989
+ return void 0;
7990
+ }
7991
+ function readDaemonLockPid(home) {
7992
+ try {
7993
+ const pid = Number(readFileSync3(join2(home, daemonLockFileName), "utf8").trim());
7994
+ return Number.isInteger(pid) && pid > 0 ? pid : void 0;
7995
+ } catch {
7996
+ return void 0;
7997
+ }
7998
+ }
7999
+ function installerScript(baseUrl) {
8000
+ return [
8001
+ "installer=$(mktemp)",
8002
+ `trap 'rm -f "$installer"' EXIT`,
8003
+ `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`)}`,
8004
+ 'sh "$installer"'
8005
+ ].join(" && ");
8006
+ }
8007
+ function installerFailure(code, signal, log3) {
8008
+ const reason = signal === null ? `exit code ${code}` : `signal ${signal}`;
8009
+ return new Error(`omnarad installer failed (${reason})${log3 === "" ? "" : `
8010
+ ${log3}`}`);
8011
+ }
8012
+ function runInstaller(report, baseUrl, token, machineId, home) {
8013
+ return new Promise((resolve3, reject) => {
8014
+ const child = spawn2("/bin/sh", ["-c", installerScript(baseUrl)], {
8015
+ stdio: ["ignore", "pipe", "pipe"],
8016
+ env: { ...process.env, OMNARA_API_URL: baseUrl, OMNARA_MACHINE_TOKEN: token }
8017
+ });
8018
+ const relay = (signal) => {
8019
+ child.kill(signal);
8020
+ };
8021
+ process.on("SIGINT", relay);
8022
+ process.on("SIGTERM", relay);
8023
+ const buffered = [];
8024
+ let transcript = "";
8025
+ let supervision;
8026
+ const enterForeground = () => {
8027
+ supervision = "foreground";
8028
+ report.stop("omnarad installed");
8029
+ report.info(daemonGuidance(machineId));
8030
+ report.info(foregroundGuidance);
8031
+ for (const [target, data] of buffered) target.write(data);
8032
+ };
8033
+ const lockWatch = setInterval(() => {
8034
+ if (supervision !== void 0 || child.pid === void 0) return;
8035
+ const daemonPid = readDaemonLockPid(home);
8036
+ if (daemonPid === void 0) return;
8037
+ const detected = classifyDaemonSupervision(daemonPid, child.pid, parentProcess);
8038
+ if (detected === "foreground") enterForeground();
8039
+ else if (detected === "service") supervision = "service";
8040
+ }, daemonLockPollMs);
8041
+ const settle = (outcome) => {
8042
+ clearInterval(lockWatch);
8043
+ process.off("SIGINT", relay);
8044
+ process.off("SIGTERM", relay);
8045
+ outcome();
8046
+ };
8047
+ const consume = (stream) => (chunk) => {
8048
+ if (supervision === "foreground") {
8049
+ stream.write(chunk);
8050
+ return;
8051
+ }
8052
+ buffered.push([stream, chunk]);
8053
+ transcript += chunk.toString();
8054
+ };
8055
+ child.stdout.on("data", consume(process.stdout));
8056
+ child.stderr.on("data", consume(process.stderr));
8057
+ child.on("error", (error) => {
8058
+ settle(() => {
8059
+ reject(new Error(`could not run the omnarad installer: ${error.message}`));
8060
+ });
8061
+ });
8062
+ child.on("close", (code, signal) => {
8063
+ settle(() => {
8064
+ const foreground = supervision === "foreground";
8065
+ if (foreground && (code === 0 || signal === "SIGINT")) {
8066
+ report.info("omnarad stopped");
8067
+ resolve3();
8068
+ } else if (foreground) {
8069
+ const reason = signal === null ? `exit code ${code}` : `signal ${signal}`;
8070
+ reject(new DaemonExitError(`omnarad exited while running in the foreground (${reason})`));
8071
+ } else if (code === 0) {
8072
+ report.stop("omnarad installed and started as a background service");
8073
+ for (const [target, data] of buffered) target.write(data);
8074
+ report.info(daemonGuidance(machineId));
8075
+ resolve3();
8076
+ } else {
8077
+ reject(installerFailure(code, signal, transcript.trim()));
8078
+ }
8079
+ });
8080
+ });
8081
+ });
8082
+ }
8083
+
7577
8084
  // src/mcp-add.ts
7578
8085
  import { isMap, isScalar as isScalar2, parseDocument } from "yaml";
7579
- import * as z10 from "zod";
8086
+ import * as z11 from "zod";
7580
8087
 
7581
8088
  // src/mcp-oauth.ts
7582
- import * as z9 from "zod";
8089
+ import * as z10 from "zod";
7583
8090
 
7584
8091
  // src/poll.ts
7585
8092
  var POLL_INTERVAL_SECONDS = 2;
7586
8093
  var MAX_CONSECUTIVE_POLL_FAILURES = 3;
7587
8094
  function sleep(seconds) {
7588
- return new Promise((resolve2) => setTimeout(resolve2, seconds * 1e3));
8095
+ return new Promise((resolve3) => setTimeout(resolve3, seconds * 1e3));
7589
8096
  }
7590
8097
  async function pollUntilDeadline(options) {
7591
8098
  const deadline = Date.parse(options.expiresAt);
@@ -7627,7 +8134,7 @@ async function authorizeMcpOAuthSecret(options) {
7627
8134
  }
7628
8135
  });
7629
8136
  }
7630
- var zBrowserFlag = z9.boolean().default(true).describe("open the authorization URL in a browser");
8137
+ var zBrowserFlag = z10.boolean().default(true).describe("open the authorization URL in a browser");
7631
8138
  function openAuthorizationUrl(report, title, url3, browser) {
7632
8139
  report.url(title, url3);
7633
8140
  if (browser) {
@@ -7663,7 +8170,7 @@ async function runMcpOAuth(context) {
7663
8170
  // src/mcp-add.ts
7664
8171
  var SERVER_KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9-]{0,31}$/;
7665
8172
  var zMcpAddBody = zMcpoAuthStartRequest.omit({ owner: true, name: true }).extend({
7666
- server_name: z10.string().regex(
8173
+ server_name: z11.string().regex(
7667
8174
  SERVER_KEY_PATTERN,
7668
8175
  "must start with a letter and contain at most 32 letters, digits, or hyphens"
7669
8176
  ).describe("MCP server key used in the agent config"),
@@ -7676,7 +8183,7 @@ function targetLabel(target) {
7676
8183
  function serverEntry(url3, secretId) {
7677
8184
  return { url: url3, auth: { type: "oauth", secret_id: secretId } };
7678
8185
  }
7679
- var zJsonRecord = z10.record(z10.string(), z10.json());
8186
+ var zJsonRecord = z11.record(z11.string(), z11.json());
7680
8187
  function prepareJsonConfig(config2, serverName, mcpUrl) {
7681
8188
  let parsedJson;
7682
8189
  try {
@@ -7840,18 +8347,18 @@ function runProfileMcpAdd(context) {
7840
8347
  }
7841
8348
 
7842
8349
  // src/skill-archive.ts
7843
- import { readdirSync, readFileSync as readFileSync3, statSync } from "node:fs";
7844
- import { basename, dirname as dirname2, join as join2, resolve } from "node:path";
8350
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync } from "node:fs";
8351
+ import { basename as basename2, dirname as dirname3, join as join3, resolve as resolve2 } from "node:path";
7845
8352
  import * as tar from "tar";
7846
- import * as z11 from "zod";
7847
- var zCreateSkillCliBody = z11.object({
8353
+ import * as z12 from "zod";
8354
+ var zCreateSkillCliBody = z12.object({
7848
8355
  owner: zSkillOwnerInput,
7849
- archive: z11.string().min(1).describe("path to a skill directory (packed automatically) or a .zip/.tar.gz archive")
8356
+ archive: z12.string().min(1).describe("path to a skill directory (packed automatically) or a .zip/.tar.gz archive")
7850
8357
  });
7851
8358
  var ARCHIVE_SUFFIXES = [".zip", ".tar.gz", ".tgz"];
7852
8359
  function assertPackable(dir) {
7853
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
7854
- const fullPath = join2(dir, entry.name);
8360
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
8361
+ const fullPath = join3(dir, entry.name);
7855
8362
  if (entry.isSymbolicLink()) {
7856
8363
  throw new CliInputError(`cannot pack ${fullPath}: symlinks are not allowed in skill archives`);
7857
8364
  }
@@ -7860,9 +8367,9 @@ function assertPackable(dir) {
7860
8367
  }
7861
8368
  }
7862
8369
  async function packDirectory(dir) {
7863
- const root = resolve(dir);
8370
+ const root = resolve2(dir);
7864
8371
  assertPackable(root);
7865
- const stream = tar.create({ cwd: dirname2(root), gzip: true, portable: true }, [basename(root)]);
8372
+ const stream = tar.create({ cwd: dirname3(root), gzip: true, portable: true }, [basename2(root)]);
7866
8373
  const chunks = [];
7867
8374
  for await (const chunk of stream) chunks.push(chunk);
7868
8375
  return Buffer.concat(chunks);
@@ -7876,28 +8383,28 @@ async function loadSkillArchive(archivePath) {
7876
8383
  }
7877
8384
  if (isDirectory) {
7878
8385
  const buffer = await packDirectory(archivePath);
7879
- return new File([new Uint8Array(buffer)], `${basename(resolve(archivePath))}.tar.gz`);
8386
+ return new File([new Uint8Array(buffer)], `${basename2(resolve2(archivePath))}.tar.gz`);
7880
8387
  }
7881
- const filename = basename(archivePath);
8388
+ const filename = basename2(archivePath);
7882
8389
  if (!ARCHIVE_SUFFIXES.some((suffix) => filename.toLowerCase().endsWith(suffix))) {
7883
8390
  throw new CliInputError(
7884
8391
  `archive must be a directory or a ${ARCHIVE_SUFFIXES.join("/")} file: ${archivePath}`
7885
8392
  );
7886
8393
  }
7887
- return new File([new Uint8Array(readFileSync3(archivePath))], filename);
8394
+ return new File([new Uint8Array(readFileSync4(archivePath))], filename);
7888
8395
  }
7889
8396
 
7890
8397
  // src/slack-integration.ts
7891
- import * as z12 from "zod";
7892
- var zSlackBody = z12.object({
7893
- app_name: z12.string().optional().describe("name for a new Slack app"),
7894
- app_configuration_token: z12.string().optional().describe("Slack app configuration token for a new app"),
7895
- icon_filename: z12.string().optional().describe("filename for the new Slack app icon"),
7896
- icon_data_base64: z12.string().optional().describe("base64-encoded Slack app icon"),
7897
- client_id: z12.string().optional().describe("existing Slack app client ID"),
7898
- client_secret: z12.string().optional().describe("existing Slack app client secret"),
7899
- signing_secret: z12.string().optional().describe("existing Slack app signing secret"),
7900
- return_to: z12.string().optional().describe("console-relative path opened after authorization"),
8398
+ import * as z13 from "zod";
8399
+ var zSlackBody = z13.object({
8400
+ app_name: z13.string().optional().describe("name for a new Slack app"),
8401
+ app_configuration_token: z13.string().optional().describe("Slack app configuration token for a new app"),
8402
+ icon_filename: z13.string().optional().describe("filename for the new Slack app icon"),
8403
+ icon_data_base64: z13.string().optional().describe("base64-encoded Slack app icon"),
8404
+ client_id: z13.string().optional().describe("existing Slack app client ID"),
8405
+ client_secret: z13.string().optional().describe("existing Slack app client secret"),
8406
+ signing_secret: z13.string().optional().describe("existing Slack app signing secret"),
8407
+ return_to: z13.string().optional().describe("console-relative path opened after authorization"),
7901
8408
  browser: zBrowserFlag
7902
8409
  });
7903
8410
  function parseRequest(body) {
@@ -7926,7 +8433,7 @@ function parseRequest(body) {
7926
8433
  if (!result2.success) {
7927
8434
  throw new CliInputError(
7928
8435
  `invalid existing Slack app parameters:
7929
- ${z12.prettifyError(result2.error)}`
8436
+ ${z13.prettifyError(result2.error)}`
7930
8437
  );
7931
8438
  }
7932
8439
  return { kind: "existing-app", body: result2.data };
@@ -7948,7 +8455,7 @@ ${z12.prettifyError(result2.error)}`
7948
8455
  if (!result.success) {
7949
8456
  throw new CliInputError(
7950
8457
  `invalid Slack app parameters:
7951
- ${z12.prettifyError(result.error)}
8458
+ ${z13.prettifyError(result.error)}
7952
8459
  Pass --app-name and --app-configuration-token, or existing app credentials.`
7953
8460
  );
7954
8461
  }
@@ -8043,7 +8550,7 @@ var commandGroups = [
8043
8550
  body: zConfigAttachment.extend({
8044
8551
  profile: zAgentProfileId.optional(),
8045
8552
  name: zAgentName.optional(),
8046
- message: z13.string().optional()
8553
+ message: z14.string().optional()
8047
8554
  }),
8048
8555
  transformBody: async ({ profile, name, message, ...attachment }, { client: client2, path }) => ({
8049
8556
  profile,
@@ -8084,7 +8591,7 @@ var commandGroups = [
8084
8591
  flowOp({
8085
8592
  verb: "mcp-add",
8086
8593
  summary: "Create an OAuth secret and add an MCP server to an agent",
8087
- path: z13.object({
8594
+ path: z14.object({
8088
8595
  orgID: zOrganizationId,
8089
8596
  projectID: zProjectId,
8090
8597
  agentID: zAgentId
@@ -8329,11 +8836,18 @@ var commandGroups = [
8329
8836
  }),
8330
8837
  op({
8331
8838
  verb: "create",
8332
- summary: "Create a machine",
8333
- fn: sdk_gen_exports.createMachine,
8334
- format: formatRecord(),
8335
- path: zCreateMachinePath,
8336
- body: zCreateMachineBody
8839
+ summary: "Create a machine with a daemon token and show how to install omnarad",
8840
+ fn: sdk_gen_exports.connectByoMachine,
8841
+ format: formatMachineSetup,
8842
+ path: zConnectByoMachinePath,
8843
+ body: zConnectByoMachineBody
8844
+ }),
8845
+ flowOp({
8846
+ verb: "create-local",
8847
+ summary: "Create a machine and install omnarad on this machine",
8848
+ path: zConnectByoMachinePath,
8849
+ body: zMachineSetupBody,
8850
+ run: runMachineCreateLocal
8337
8851
  }),
8338
8852
  op({
8339
8853
  verb: "update",
@@ -8546,7 +9060,7 @@ var commandGroups = [
8546
9060
  flowOp({
8547
9061
  verb: "mcp-oauth",
8548
9062
  summary: "Create a secret through an MCP server OAuth flow",
8549
- path: z13.object({ orgID: zOrganizationId }),
9063
+ path: z14.object({ orgID: zOrganizationId }),
8550
9064
  body: zMcpOAuthBody,
8551
9065
  run: runMcpOAuth
8552
9066
  })
@@ -8660,7 +9174,7 @@ var commandGroups = [
8660
9174
  flowOp({
8661
9175
  verb: "mcp-add",
8662
9176
  summary: "Create an OAuth secret and add an MCP server to an agent profile",
8663
- path: z13.object({
9177
+ path: z14.object({
8664
9178
  orgID: zOrganizationId,
8665
9179
  projectID: zProjectId,
8666
9180
  agentProfileID: zAgentProfileId
@@ -8672,7 +9186,7 @@ var commandGroups = [
8672
9186
  verb: "slack",
8673
9187
  aliases: ["slack-setup"],
8674
9188
  summary: "Connect Slack to an agent profile through OAuth",
8675
- path: z13.object({
9189
+ path: z14.object({
8676
9190
  orgID: zOrganizationId,
8677
9191
  projectID: zProjectId,
8678
9192
  agentProfileID: zAgentProfileId
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnara",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Command-line interface for Omnara: launch and manage agents, organizations, integrations, and MCP servers",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://omnara.com",