vibora 7.1.1 → 7.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/vibora.js CHANGED
@@ -32629,7 +32629,7 @@ function installUv() {
32629
32629
  var package_default = {
32630
32630
  name: "vibora",
32631
32631
  private: true,
32632
- version: "7.1.1",
32632
+ version: "7.1.3",
32633
32633
  description: "Harness Attention. Orchestrate Agents. Ship.",
32634
32634
  license: "PolyForm-Shield-1.0.0",
32635
32635
  type: "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibora",
3
- "version": "7.1.1",
3
+ "version": "7.1.3",
4
4
  "description": "Harness Attention. Orchestrate Agents. Ship.",
5
5
  "license": "PolyForm-Shield-1.0.0",
6
6
  "repository": {
package/server/index.js CHANGED
@@ -9506,7 +9506,7 @@ var __classPrivateFieldSet = function(receiver, state, value, kind2, f) {
9506
9506
  }
9507
9507
  }, startsWithSchemeRegexp, isAbsoluteURL = (url) => {
9508
9508
  return startsWithSchemeRegexp.test(url);
9509
- }, sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)), validatePositiveInteger = (name, n) => {
9509
+ }, sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)), validatePositiveInteger = (name, n) => {
9510
9510
  if (typeof n !== "number" || !Number.isInteger(n)) {
9511
9511
  throw new CloudflareError(`${name} must be an integer`);
9512
9512
  }
@@ -9571,8 +9571,8 @@ var init_core = __esm(() => {
9571
9571
  init();
9572
9572
  APIPromise = class APIPromise extends Promise {
9573
9573
  constructor(responsePromise, parseResponse = defaultParseResponse) {
9574
- super((resolve5) => {
9575
- resolve5(null);
9574
+ super((resolve6) => {
9575
+ resolve6(null);
9576
9576
  });
9577
9577
  this.responsePromise = responsePromise;
9578
9578
  this.parseResponse = parseResponse;
@@ -176605,17 +176605,15 @@ async function fetchDockerApiStats() {
176605
176605
  if (!listResponse.ok)
176606
176606
  return null;
176607
176607
  const containerList = await listResponse.json();
176608
- const containers = [];
176609
- for (const container of containerList) {
176610
- if (container.State !== "running")
176611
- continue;
176608
+ const runningContainers = containerList.filter((c) => c.State === "running");
176609
+ const statsPromises = runningContainers.map(async (container) => {
176612
176610
  try {
176613
176611
  const statsUrl = `http://localhost/containers/${container.Id}/stats?stream=false`;
176614
176612
  const statsResponse = await fetch(statsUrl, {
176615
176613
  unix: socketPath
176616
176614
  });
176617
176615
  if (!statsResponse.ok)
176618
- continue;
176616
+ return null;
176619
176617
  const stats = await statsResponse.json();
176620
176618
  const cpuDelta = stats.cpu_stats.cpu_usage.total_usage - stats.precpu_stats.cpu_usage.total_usage;
176621
176619
  const systemDelta = stats.cpu_stats.system_cpu_usage - stats.precpu_stats.system_cpu_usage;
@@ -176625,18 +176623,20 @@ async function fetchDockerApiStats() {
176625
176623
  const memoryMB = memoryBytes / (1024 * 1024);
176626
176624
  const memoryLimitMB = memoryLimit / (1024 * 1024);
176627
176625
  const memoryPercent = memoryLimit > 0 ? memoryBytes / memoryLimit * 100 : 0;
176628
- containers.push({
176626
+ return {
176629
176627
  id: container.Id.slice(0, 12),
176630
176628
  name: (container.Names[0] || "unknown").replace(/^\//, ""),
176631
176629
  cpuPercent: Math.round(cpuPercent * 10) / 10,
176632
176630
  memoryMB: Math.round(memoryMB * 10) / 10,
176633
176631
  memoryLimit: Math.round(memoryLimitMB * 10) / 10,
176634
176632
  memoryPercent: Math.round(memoryPercent * 10) / 10
176635
- });
176633
+ };
176636
176634
  } catch {
176637
- continue;
176635
+ return null;
176638
176636
  }
176639
- }
176637
+ });
176638
+ const results = await Promise.all(statsPromises);
176639
+ const containers = results.filter((c) => c !== null);
176640
176640
  return containers;
176641
176641
  } catch {
176642
176642
  return null;
@@ -177308,6 +177308,60 @@ var nanoid = (size = 21) => {
177308
177308
  import { readFile as readFile2, access } from "fs/promises";
177309
177309
  import { join as join16 } from "path";
177310
177310
  init_logger2();
177311
+
177312
+ // server/lib/env-expand.ts
177313
+ function expandEnvVar(str, env) {
177314
+ const braceMatch = str.match(/^\$\{([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-=])(.+))?\}$/);
177315
+ if (braceMatch) {
177316
+ const varName = braceMatch[1];
177317
+ const operator = braceMatch[2];
177318
+ const defaultValue = braceMatch[3];
177319
+ if (env && varName in env) {
177320
+ const value = env[varName];
177321
+ if (operator?.startsWith(":") && value === "") {
177322
+ return defaultValue ?? null;
177323
+ }
177324
+ return value;
177325
+ }
177326
+ if (defaultValue !== undefined) {
177327
+ return defaultValue;
177328
+ }
177329
+ return null;
177330
+ }
177331
+ const simpleMatch = str.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
177332
+ if (simpleMatch) {
177333
+ const varName = simpleMatch[1];
177334
+ if (env && varName in env) {
177335
+ return env[varName];
177336
+ }
177337
+ return null;
177338
+ }
177339
+ return str;
177340
+ }
177341
+ function splitRespectingEnvVars(str, delimiter = ":") {
177342
+ const parts = [];
177343
+ let current = "";
177344
+ let braceDepth = 0;
177345
+ for (let i = 0;i < str.length; i++) {
177346
+ const char = str[i];
177347
+ if (char === "{" && i > 0 && str[i - 1] === "$") {
177348
+ braceDepth++;
177349
+ current += char;
177350
+ } else if (char === "}" && braceDepth > 0) {
177351
+ braceDepth--;
177352
+ current += char;
177353
+ } else if (char === delimiter && braceDepth === 0) {
177354
+ parts.push(current);
177355
+ current = "";
177356
+ } else {
177357
+ current += char;
177358
+ }
177359
+ }
177360
+ parts.push(current);
177361
+ return parts;
177362
+ }
177363
+
177364
+ // server/services/compose-parser.ts
177311
177365
  var COMPOSE_FILE_NAMES = ["compose.yml", "compose.yaml", "docker-compose.yml", "docker-compose.yaml"];
177312
177366
  async function findComposeFile(repoPath) {
177313
177367
  for (const fileName of COMPOSE_FILE_NAMES) {
@@ -177319,8 +177373,23 @@ async function findComposeFile(repoPath) {
177319
177373
  }
177320
177374
  return null;
177321
177375
  }
177376
+ function parsePortValue(value) {
177377
+ const expanded = expandEnvVar(value);
177378
+ if (expanded === null) {
177379
+ return null;
177380
+ }
177381
+ const port = parseInt(expanded, 10);
177382
+ if (isNaN(port) || port <= 0 || port > 65535) {
177383
+ return null;
177384
+ }
177385
+ return port;
177386
+ }
177322
177387
  function parsePort(port) {
177323
177388
  if (typeof port === "number") {
177389
+ if (port <= 0 || port > 65535) {
177390
+ log2.deploy.warn("Invalid port number", { port });
177391
+ return null;
177392
+ }
177324
177393
  return { container: port };
177325
177394
  }
177326
177395
  if (typeof port === "string") {
@@ -177333,28 +177402,34 @@ function parsePort(port) {
177333
177402
  protocol = "udp";
177334
177403
  portStr = port.slice(0, -4);
177335
177404
  }
177336
- if (portStr.includes(":")) {
177337
- const parts = portStr.split(":");
177338
- const containerPort = parseInt(parts[parts.length - 1], 10);
177339
- const hostPort = parseInt(parts[parts.length - 2], 10);
177340
- if (!isNaN(containerPort)) {
177405
+ const parts = splitRespectingEnvVars(portStr);
177406
+ if (parts.length >= 2) {
177407
+ const containerPort = parsePortValue(parts[parts.length - 1]);
177408
+ const hostPort = parsePortValue(parts[parts.length - 2]);
177409
+ if (containerPort !== null) {
177341
177410
  return {
177342
177411
  container: containerPort,
177343
- host: isNaN(hostPort) ? undefined : hostPort,
177412
+ host: hostPort ?? undefined,
177344
177413
  protocol
177345
177414
  };
177346
177415
  }
177416
+ log2.deploy.warn("Could not parse port with env var reference", { port: portStr });
177347
177417
  } else {
177348
- const containerPort = parseInt(portStr, 10);
177349
- if (!isNaN(containerPort)) {
177418
+ const containerPort = parsePortValue(portStr);
177419
+ if (containerPort !== null) {
177350
177420
  return { container: containerPort, protocol };
177351
177421
  }
177422
+ log2.deploy.warn("Could not parse port value", { port: portStr });
177352
177423
  }
177353
177424
  }
177354
177425
  if (typeof port === "object" && port !== null) {
177355
177426
  const portObj = port;
177356
177427
  const target = portObj.target ?? portObj.container_port;
177357
177428
  if (typeof target === "number") {
177429
+ if (target <= 0 || target > 65535) {
177430
+ log2.deploy.warn("Invalid port number in long syntax", { target });
177431
+ return null;
177432
+ }
177358
177433
  return {
177359
177434
  container: target,
177360
177435
  host: typeof portObj.published === "number" ? portObj.published : undefined,
@@ -177595,14 +177670,14 @@ async function runDocker(args, options = {}) {
177595
177670
  // server/services/docker-swarm.ts
177596
177671
  import { spawn as spawn5 } from "child_process";
177597
177672
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
177598
- import { join as join17 } from "path";
177673
+ import { join as join17, resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
177599
177674
  init_logger2();
177600
177675
  async function runDocker2(args, options = {}, onOutput) {
177601
177676
  if (options.signal?.aborted) {
177602
177677
  return { stdout: "", stderr: "Aborted", exitCode: -1, aborted: true };
177603
177678
  }
177604
177679
  log2.deploy.debug("Running docker command", { args, cwd: options.cwd });
177605
- return new Promise((resolve5) => {
177680
+ return new Promise((resolve6) => {
177606
177681
  const proc2 = spawn5("docker", args, {
177607
177682
  cwd: options.cwd,
177608
177683
  env: {
@@ -177644,12 +177719,12 @@ async function runDocker2(args, options = {}, onOutput) {
177644
177719
  });
177645
177720
  proc2.on("close", (code) => {
177646
177721
  options.signal?.removeEventListener("abort", abortHandler);
177647
- resolve5({ stdout, stderr, exitCode: code ?? 0, aborted });
177722
+ resolve6({ stdout, stderr, exitCode: code ?? 0, aborted });
177648
177723
  });
177649
177724
  proc2.on("error", (err) => {
177650
177725
  options.signal?.removeEventListener("abort", abortHandler);
177651
177726
  log2.deploy.error("Docker spawn error", { error: String(err) });
177652
- resolve5({ stdout, stderr, exitCode: 1, aborted });
177727
+ resolve6({ stdout, stderr, exitCode: 1, aborted });
177653
177728
  });
177654
177729
  });
177655
177730
  }
@@ -177725,6 +177800,9 @@ async function generateSwarmComposeFile(cwd, composeFile, projectName, externalN
177725
177800
  });
177726
177801
  serviceConfig.depends_on = Object.keys(serviceConfig.depends_on);
177727
177802
  }
177803
+ if (Array.isArray(serviceConfig.volumes)) {
177804
+ serviceConfig.volumes = serviceConfig.volumes.map((vol) => resolveVolumeEntry(vol, cwd));
177805
+ }
177728
177806
  const unsupportedFields = [
177729
177807
  "container_name",
177730
177808
  "links",
@@ -177972,7 +178050,55 @@ async function waitForServicesHealthy(stackName, timeoutMs = 300000, signal) {
177972
178050
  return { healthy: false, failedServices };
177973
178051
  }
177974
178052
  function sleep(ms) {
177975
- return new Promise((resolve5) => setTimeout(resolve5, ms));
178053
+ return new Promise((r) => setTimeout(r, ms));
178054
+ }
178055
+ function resolveVolumePath(volumePath, basePath) {
178056
+ const expanded = expandEnvVar(volumePath);
178057
+ const pathToCheck = expanded ?? volumePath;
178058
+ if (!pathToCheck.includes("/") && !pathToCheck.startsWith(".")) {
178059
+ return volumePath;
178060
+ }
178061
+ if (expanded === null && volumePath.includes("${")) {
178062
+ return volumePath;
178063
+ }
178064
+ if (isAbsolute2(pathToCheck)) {
178065
+ return expanded ?? volumePath;
178066
+ }
178067
+ return resolve5(basePath, pathToCheck);
178068
+ }
178069
+ function resolveVolumeEntry(volume, basePath) {
178070
+ if (typeof volume === "string") {
178071
+ const parts = splitRespectingEnvVars(volume);
178072
+ if (parts.length >= 2) {
178073
+ const hostPath = parts[0];
178074
+ const containerPath = parts[1];
178075
+ const options = parts.slice(2).join(":");
178076
+ const resolvedHost = resolveVolumePath(hostPath, basePath);
178077
+ if (resolvedHost !== hostPath) {
178078
+ log2.deploy.debug("Resolved relative volume path", {
178079
+ original: hostPath,
178080
+ resolved: resolvedHost
178081
+ });
178082
+ }
178083
+ return options ? `${resolvedHost}:${containerPath}:${options}` : `${resolvedHost}:${containerPath}`;
178084
+ }
178085
+ return volume;
178086
+ }
178087
+ if (typeof volume === "object" && volume !== null) {
178088
+ const vol = volume;
178089
+ if (vol.type === "bind" && typeof vol.source === "string") {
178090
+ const resolvedSource = resolveVolumePath(vol.source, basePath);
178091
+ if (resolvedSource !== vol.source) {
178092
+ log2.deploy.debug("Resolved relative volume path (long syntax)", {
178093
+ original: vol.source,
178094
+ resolved: resolvedSource
178095
+ });
178096
+ return { ...vol, source: resolvedSource };
178097
+ }
178098
+ }
178099
+ return vol;
178100
+ }
178101
+ return volume;
177976
178102
  }
177977
178103
  async function addCloudflaredToStack(swarmFilePath, config) {
177978
178104
  try {
@@ -178522,17 +178648,17 @@ async function cancelDeployment(deploymentId) {
178522
178648
  log2.deploy.debug("Killing process", { deploymentId, pid: proc2.pid });
178523
178649
  try {
178524
178650
  proc2.kill("SIGTERM");
178525
- await new Promise((resolve5) => {
178651
+ await new Promise((resolve6) => {
178526
178652
  const timeout = setTimeout(() => {
178527
178653
  if (!proc2.killed) {
178528
178654
  log2.deploy.debug("Force killing process", { deploymentId, pid: proc2.pid });
178529
178655
  proc2.kill("SIGKILL");
178530
178656
  }
178531
- resolve5();
178657
+ resolve6();
178532
178658
  }, 3000);
178533
178659
  proc2.once("exit", () => {
178534
178660
  clearTimeout(timeout);
178535
- resolve5();
178661
+ resolve6();
178536
178662
  });
178537
178663
  });
178538
178664
  } catch (err) {
@@ -178616,7 +178742,7 @@ function getProjectName(appId) {
178616
178742
  return `vibora-${appId.slice(0, 8).toLowerCase()}`;
178617
178743
  }
178618
178744
  async function getGitCommit(repoPath) {
178619
- return new Promise((resolve5) => {
178745
+ return new Promise((resolve6) => {
178620
178746
  const proc2 = spawn6("git", ["log", "-1", "--format=%H%n%s"], { cwd: repoPath });
178621
178747
  let stdout = "";
178622
178748
  proc2.stdout.on("data", (data) => {
@@ -178624,18 +178750,18 @@ async function getGitCommit(repoPath) {
178624
178750
  });
178625
178751
  proc2.on("close", (code) => {
178626
178752
  if (code !== 0) {
178627
- resolve5(null);
178753
+ resolve6(null);
178628
178754
  } else {
178629
178755
  const lines = stdout.trim().split(`
178630
178756
  `);
178631
- resolve5({
178757
+ resolve6({
178632
178758
  hash: lines[0]?.slice(0, 7) ?? "",
178633
178759
  message: lines[1] ?? ""
178634
178760
  });
178635
178761
  }
178636
178762
  });
178637
178763
  proc2.on("error", () => {
178638
- resolve5(null);
178764
+ resolve6(null);
178639
178765
  });
178640
178766
  });
178641
178767
  }
@@ -178756,8 +178882,13 @@ async function deployApp(appId, options = {}, onProgress) {
178756
178882
  where: eq(appServices.appId, appId)
178757
178883
  });
178758
178884
  for (const service of services) {
178759
- if (service.exposed && service.domain && !service.containerPort) {
178760
- throw new Error(`Service "${service.serviceName}" is exposed with domain "${service.domain}" but has no container port configured. ` + `Add a port mapping to your compose file or configure the container port in the service settings.`);
178885
+ if (service.exposed && service.domain) {
178886
+ if (!service.containerPort) {
178887
+ throw new Error(`Service "${service.serviceName}" is exposed with domain "${service.domain}" but has no container port configured. ` + `Add a port mapping to your compose file or configure the container port in the service settings.`);
178888
+ }
178889
+ if (service.containerPort <= 0 || service.containerPort > 65535) {
178890
+ throw new Error(`Service "${service.serviceName}" has invalid container port ${service.containerPort}. ` + `Port must be between 1 and 65535. Check your compose file port configuration.`);
178891
+ }
178761
178892
  }
178762
178893
  }
178763
178894
  const serviceStatuses = await stackServices(projectName);
@@ -180189,11 +180320,11 @@ ensureLatestSettings();
180189
180320
  var PORT = getSettingByKey("port");
180190
180321
  var HOST = process.env.HOST || "localhost";
180191
180322
  async function checkPortAvailable(port, host) {
180192
- return new Promise((resolve5) => {
180323
+ return new Promise((resolve6) => {
180193
180324
  const server = createServer();
180194
- server.once("error", () => resolve5(false));
180325
+ server.once("error", () => resolve6(false));
180195
180326
  server.once("listening", () => {
180196
- server.close(() => resolve5(true));
180327
+ server.close(() => resolve6(true));
180197
180328
  });
180198
180329
  server.listen(port, host);
180199
180330
  });