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 +1 -1
- package/package.json +1 -1
- package/server/index.js +168 -37
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.
|
|
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
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((
|
|
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((
|
|
9575
|
-
|
|
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
|
|
176609
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177337
|
-
|
|
177338
|
-
const containerPort =
|
|
177339
|
-
const hostPort =
|
|
177340
|
-
if (
|
|
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:
|
|
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 =
|
|
177349
|
-
if (
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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
|
-
|
|
178657
|
+
resolve6();
|
|
178532
178658
|
}, 3000);
|
|
178533
178659
|
proc2.once("exit", () => {
|
|
178534
178660
|
clearTimeout(timeout);
|
|
178535
|
-
|
|
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((
|
|
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
|
-
|
|
178753
|
+
resolve6(null);
|
|
178628
178754
|
} else {
|
|
178629
178755
|
const lines = stdout.trim().split(`
|
|
178630
178756
|
`);
|
|
178631
|
-
|
|
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
|
-
|
|
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
|
|
178760
|
-
|
|
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((
|
|
180323
|
+
return new Promise((resolve6) => {
|
|
180193
180324
|
const server = createServer();
|
|
180194
|
-
server.once("error", () =>
|
|
180325
|
+
server.once("error", () => resolve6(false));
|
|
180195
180326
|
server.once("listening", () => {
|
|
180196
|
-
server.close(() =>
|
|
180327
|
+
server.close(() => resolve6(true));
|
|
180197
180328
|
});
|
|
180198
180329
|
server.listen(port, host);
|
|
180199
180330
|
});
|