openmates 0.18.0-alpha.0 → 0.18.0-alpha.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/{chunk-RLOO6QKC.js → chunk-XKIFO4JO.js} +126 -91
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -24301,7 +24301,7 @@ import { stdin as stdin3, stdout as stdout2 } from "process";
|
|
|
24301
24301
|
import { existsSync as existsSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
24302
24302
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
24303
24303
|
import { basename as basename3, dirname as dirname9 } from "path";
|
|
24304
|
-
import { createHash as createHash14, randomBytes as randomBytes9, randomUUID as
|
|
24304
|
+
import { createHash as createHash14, randomBytes as randomBytes9, randomUUID as randomUUID15 } from "crypto";
|
|
24305
24305
|
import { arch as arch2, platform as platform3 } from "os";
|
|
24306
24306
|
import { parse as parseYaml } from "yaml";
|
|
24307
24307
|
import WebSocket2 from "ws";
|
|
@@ -26479,9 +26479,9 @@ function formatTs(ts) {
|
|
|
26479
26479
|
}
|
|
26480
26480
|
|
|
26481
26481
|
// src/server.ts
|
|
26482
|
-
import { execFileSync as
|
|
26483
|
-
import { createHash as createHash12, randomBytes as randomBytes8, randomUUID as
|
|
26484
|
-
import { appendFileSync, chmodSync as
|
|
26482
|
+
import { execFileSync as execFileSync4, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
|
|
26483
|
+
import { createHash as createHash12, randomBytes as randomBytes8, randomUUID as randomUUID11 } from "crypto";
|
|
26484
|
+
import { appendFileSync, chmodSync as chmodSync5, closeSync as closeSync2, copyFileSync as copyFileSync2, cpSync, existsSync as existsSync9, mkdirSync as mkdirSync6, mkdtempSync, openSync as openSync2, readFileSync as readFileSync7, readSync, readdirSync as readdirSync4, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
26485
26485
|
import { createInterface as createInterface3 } from "readline";
|
|
26486
26486
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
26487
26487
|
import { homedir as homedir6 } from "os";
|
|
@@ -26955,12 +26955,11 @@ function planUpdate(input) {
|
|
|
26955
26955
|
function planBackup(input) {
|
|
26956
26956
|
const role = parseServerRole(input.role);
|
|
26957
26957
|
const contentsByRole = {
|
|
26958
|
-
core: ["postgres-dump", "
|
|
26959
|
-
upload: ["
|
|
26960
|
-
preview: ["runtime-env", "runtime-config", "
|
|
26958
|
+
core: ["postgres-dump", "runtime-env", "runtime-config", "manifest", "checksums"],
|
|
26959
|
+
upload: ["runtime-env", "runtime-config", "manifest", "checksums"],
|
|
26960
|
+
preview: ["runtime-env", "runtime-config", "manifest", "checksums"]
|
|
26961
26961
|
};
|
|
26962
26962
|
const contents = [...contentsByRole[role]];
|
|
26963
|
-
if (input.includeObservability) contents.push("openobserve-data", "prometheus-data");
|
|
26964
26963
|
return { role, contents, fileMode: 384 };
|
|
26965
26964
|
}
|
|
26966
26965
|
function planRestore(input) {
|
|
@@ -27193,9 +27192,38 @@ function shouldAutoInstallRuntimeMonitoringServices(env) {
|
|
|
27193
27192
|
return env.OPENMATES_SKIP_RUNTIME_MONITORING !== "1";
|
|
27194
27193
|
}
|
|
27195
27194
|
|
|
27195
|
+
// src/serverBackupArchive.ts
|
|
27196
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
27197
|
+
import { chmodSync as chmodSync3, lstatSync, readdirSync as readdirSync3, renameSync, rmSync as rmSync4 } from "fs";
|
|
27198
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
27199
|
+
function assertRegularBackupTree(path2) {
|
|
27200
|
+
const stat2 = lstatSync(path2);
|
|
27201
|
+
if (stat2.isDirectory()) {
|
|
27202
|
+
for (const entry of readdirSync3(path2)) assertRegularBackupTree(`${path2}/${entry}`);
|
|
27203
|
+
return;
|
|
27204
|
+
}
|
|
27205
|
+
if (!stat2.isFile() || stat2.nlink !== 1) {
|
|
27206
|
+
throw new Error(`Backup archive refused unsafe entry: ${path2}`);
|
|
27207
|
+
}
|
|
27208
|
+
}
|
|
27209
|
+
function publishServerBackupArchive(sourceDir, archivePath, options = {}) {
|
|
27210
|
+
assertRegularBackupTree(sourceDir);
|
|
27211
|
+
const temporaryArchivePath = `${archivePath}.tmp-${randomUUID8()}`;
|
|
27212
|
+
const previousUmask = process.umask(63);
|
|
27213
|
+
try {
|
|
27214
|
+
execFileSync3(options.tarCommand ?? "tar", ["-czf", temporaryArchivePath, "-C", sourceDir, "."], { stdio: "pipe" });
|
|
27215
|
+
chmodSync3(temporaryArchivePath, 384);
|
|
27216
|
+
renameSync(temporaryArchivePath, archivePath);
|
|
27217
|
+
chmodSync3(archivePath, 384);
|
|
27218
|
+
} finally {
|
|
27219
|
+
process.umask(previousUmask);
|
|
27220
|
+
rmSync4(temporaryArchivePath, { force: true });
|
|
27221
|
+
}
|
|
27222
|
+
}
|
|
27223
|
+
|
|
27196
27224
|
// src/serverHealth.ts
|
|
27197
27225
|
import dnsModule, { promises as dns } from "dns";
|
|
27198
|
-
import { createHmac as createHmac4, randomUUID as
|
|
27226
|
+
import { createHmac as createHmac4, randomUUID as randomUUID9 } from "crypto";
|
|
27199
27227
|
import { promises as fs } from "fs";
|
|
27200
27228
|
import { isIP } from "net";
|
|
27201
27229
|
import { request as httpsRequest } from "https";
|
|
@@ -27578,7 +27606,7 @@ async function resolveGenericWebhookTarget(rawUrl, allowLocalDevelopmentFixture
|
|
|
27578
27606
|
async function sendGenericWebhook(target, secret, payload, allowLocalDevelopmentFixture = false) {
|
|
27579
27607
|
const { url, addresses } = await resolveGenericWebhookTarget(target, allowLocalDevelopmentFixture);
|
|
27580
27608
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
27581
|
-
const eventId =
|
|
27609
|
+
const eventId = randomUUID9();
|
|
27582
27610
|
const signed = signRuntimeWebhookPayload(payload, secret, timestamp, eventId);
|
|
27583
27611
|
const selected = addresses[0];
|
|
27584
27612
|
await new Promise((resolve11, reject) => {
|
|
@@ -27787,7 +27815,7 @@ function signRuntimeWebhookPayload(payload, secret, timestamp, eventId) {
|
|
|
27787
27815
|
|
|
27788
27816
|
// src/serverUpdateState.ts
|
|
27789
27817
|
import { randomBytes as randomBytes7 } from "crypto";
|
|
27790
|
-
import { chmodSync as
|
|
27818
|
+
import { chmodSync as chmodSync4, closeSync, existsSync as existsSync8, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync6, renameSync as renameSync2, rmSync as rmSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
27791
27819
|
import { dirname as dirname5, join as join6 } from "path";
|
|
27792
27820
|
function serverUpdateStatusFile(installPath, role) {
|
|
27793
27821
|
return join6(installPath, ".openmates", `${role}-update-status.json`);
|
|
@@ -27811,8 +27839,8 @@ function writeServerUpdateStatus(installPath, role, status) {
|
|
|
27811
27839
|
const temporaryPath = `${filePath}.${process.pid}.${randomBytes7(4).toString("hex")}.tmp`;
|
|
27812
27840
|
writeFileSync4(temporaryPath, `${JSON.stringify({ role, updated_at: (/* @__PURE__ */ new Date()).toISOString(), ...status }, null, 2)}
|
|
27813
27841
|
`, { mode: 384 });
|
|
27814
|
-
|
|
27815
|
-
|
|
27842
|
+
renameSync2(temporaryPath, filePath);
|
|
27843
|
+
chmodSync4(filePath, 384);
|
|
27816
27844
|
}
|
|
27817
27845
|
function acquireServerUpdateLock(installPath) {
|
|
27818
27846
|
const stateDir2 = join6(installPath, ".openmates");
|
|
@@ -27839,13 +27867,13 @@ function acquireServerUpdateLock(installPath) {
|
|
|
27839
27867
|
return () => {
|
|
27840
27868
|
closeSync(descriptor);
|
|
27841
27869
|
if (existsSync8(lockPath) && readFileSync6(lockPath, "utf8").trim() === ownershipToken) {
|
|
27842
|
-
|
|
27870
|
+
rmSync5(lockPath);
|
|
27843
27871
|
}
|
|
27844
27872
|
};
|
|
27845
27873
|
}
|
|
27846
27874
|
|
|
27847
27875
|
// src/serverQuickTest.ts
|
|
27848
|
-
import { randomUUID as
|
|
27876
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
27849
27877
|
var QUICK_TEST_RESPONSE_TIMEOUT_MS = 12e4;
|
|
27850
27878
|
var QUICK_TEST_WEB_QUERY = "site:openmates.org OpenMates";
|
|
27851
27879
|
var QUICK_TEST_EXPECTED_RESPONSE = "server quick test passed";
|
|
@@ -27911,7 +27939,7 @@ function decideQuickServerTestAction(input) {
|
|
|
27911
27939
|
async function runQuickServerTest(client, options = {}) {
|
|
27912
27940
|
const now = options.now ?? Date.now;
|
|
27913
27941
|
const checks = [];
|
|
27914
|
-
const chatId =
|
|
27942
|
+
const chatId = randomUUID10();
|
|
27915
27943
|
let chatMayExist = false;
|
|
27916
27944
|
checks.push({ id: "account.session", status: "passed", duration_ms: 0 });
|
|
27917
27945
|
const createStarted = now();
|
|
@@ -28042,6 +28070,7 @@ var HEALTH_REQUEST_TIMEOUT_MS = 5e3;
|
|
|
28042
28070
|
var CHECKSUM_BUFFER_BYTES = 1024 * 1024;
|
|
28043
28071
|
var ENV_BACKUP_PREFIX = ".env.openmates-backup-";
|
|
28044
28072
|
var ENV_BACKUP_RETENTION_COUNT = 5;
|
|
28073
|
+
var BACKUP_FORMAT_VERSION = 2;
|
|
28045
28074
|
var IMAGE_CHANNEL_TAGS = {
|
|
28046
28075
|
stable: MAIN_BRANCH,
|
|
28047
28076
|
main: MAIN_BRANCH,
|
|
@@ -28268,7 +28297,7 @@ function beginEngineeringRuntimeOperation(installPath, operationType, services)
|
|
|
28268
28297
|
"dev-stack"
|
|
28269
28298
|
];
|
|
28270
28299
|
for (const service of services) args.push("--service", service);
|
|
28271
|
-
const output =
|
|
28300
|
+
const output = execFileSync4("python3", args, {
|
|
28272
28301
|
cwd: installPath,
|
|
28273
28302
|
encoding: "utf-8",
|
|
28274
28303
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -28279,7 +28308,7 @@ function beginEngineeringRuntimeOperation(installPath, operationType, services)
|
|
|
28279
28308
|
}
|
|
28280
28309
|
function finishEngineeringRuntimeOperation(installPath, operationKey, status) {
|
|
28281
28310
|
const manager = join7(installPath, "scripts", "engineering_control_plane.py");
|
|
28282
|
-
|
|
28311
|
+
execFileSync4(
|
|
28283
28312
|
"python3",
|
|
28284
28313
|
[manager, "operation", "update", "--operation-key", operationKey, "--status", status],
|
|
28285
28314
|
{ cwd: installPath, stdio: ["ignore", "ignore", "pipe"] }
|
|
@@ -28939,13 +28968,13 @@ function targetSourceLinks(imageTag, templateRef) {
|
|
|
28939
28968
|
};
|
|
28940
28969
|
}
|
|
28941
28970
|
function installedImageMetadata(input) {
|
|
28942
|
-
const containerId =
|
|
28971
|
+
const containerId = execFileSync4(
|
|
28943
28972
|
"docker",
|
|
28944
28973
|
[...composeArgs(input.installPath, input.withOverrides, "image", input.role), "ps", "-q", ROLE_PROVENANCE_SERVICE[input.role]],
|
|
28945
28974
|
{ cwd: input.installPath, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
|
|
28946
28975
|
).trim();
|
|
28947
28976
|
if (!containerId) throw new Error("updated_container_unavailable");
|
|
28948
|
-
const labels = JSON.parse(
|
|
28977
|
+
const labels = JSON.parse(execFileSync4(
|
|
28949
28978
|
"docker",
|
|
28950
28979
|
["inspect", "--format", "{{json .Config.Labels}}", containerId],
|
|
28951
28980
|
{ cwd: input.installPath, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
|
|
@@ -29012,9 +29041,9 @@ function readEnvContent(installPath) {
|
|
|
29012
29041
|
return existsSync9(envPath) ? readFileSync7(envPath, "utf-8") : "";
|
|
29013
29042
|
}
|
|
29014
29043
|
function pruneEnvBackups(installPath) {
|
|
29015
|
-
const backups =
|
|
29044
|
+
const backups = readdirSync4(installPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.startsWith(ENV_BACKUP_PREFIX)).map((entry) => entry.name).sort();
|
|
29016
29045
|
for (const backup of backups.slice(0, Math.max(0, backups.length - ENV_BACKUP_RETENTION_COUNT))) {
|
|
29017
|
-
|
|
29046
|
+
rmSync6(join7(installPath, backup), { force: true });
|
|
29018
29047
|
}
|
|
29019
29048
|
}
|
|
29020
29049
|
function backupEnvFile(installPath) {
|
|
@@ -29022,7 +29051,7 @@ function backupEnvFile(installPath) {
|
|
|
29022
29051
|
if (!existsSync9(envPath)) return null;
|
|
29023
29052
|
const backupPath = join7(installPath, `${ENV_BACKUP_PREFIX}${nowStamp()}`);
|
|
29024
29053
|
copyFileSync2(envPath, backupPath);
|
|
29025
|
-
|
|
29054
|
+
chmodSync5(backupPath, 384);
|
|
29026
29055
|
pruneEnvBackups(installPath);
|
|
29027
29056
|
return backupPath;
|
|
29028
29057
|
}
|
|
@@ -29030,7 +29059,7 @@ function writeEnvContent(installPath, content) {
|
|
|
29030
29059
|
const envPath = envPathForInstall(installPath);
|
|
29031
29060
|
mkdirSync6(dirname6(envPath), { recursive: true });
|
|
29032
29061
|
writeFileSync5(envPath, content, { mode: 384 });
|
|
29033
|
-
|
|
29062
|
+
chmodSync5(envPath, 384);
|
|
29034
29063
|
}
|
|
29035
29064
|
function writeDeploymentModeEnv(installPath, deploymentMode, overlayPath) {
|
|
29036
29065
|
let content = readEnvContent(installPath);
|
|
@@ -29203,7 +29232,7 @@ for item in checks:
|
|
|
29203
29232
|
print(json.dumps({"ok": True, "presence": presence}))
|
|
29204
29233
|
`;
|
|
29205
29234
|
try {
|
|
29206
|
-
const output =
|
|
29235
|
+
const output = execFileSync4(
|
|
29207
29236
|
"docker",
|
|
29208
29237
|
["exec", "-e", `OPENMATES_SECRET_CHECKS=${JSON.stringify(checks)}`, container, "python", "-c", script],
|
|
29209
29238
|
{ encoding: "utf-8", timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -29258,7 +29287,7 @@ function hashFile(path2) {
|
|
|
29258
29287
|
function writeChecksums(rootDir) {
|
|
29259
29288
|
const lines = [];
|
|
29260
29289
|
const walk = (dir) => {
|
|
29261
|
-
for (const entry of
|
|
29290
|
+
for (const entry of readdirSync4(dir, { withFileTypes: true })) {
|
|
29262
29291
|
const path2 = join7(dir, entry.name);
|
|
29263
29292
|
if (entry.isDirectory()) {
|
|
29264
29293
|
walk(path2);
|
|
@@ -29296,19 +29325,20 @@ function createServerBackup(installPath, role, options = {}) {
|
|
|
29296
29325
|
const backupDir = roleBackupDir(installPath, role);
|
|
29297
29326
|
mkdirSync6(backupDir, { recursive: true, mode: 448 });
|
|
29298
29327
|
const archivePath = options.output ? resolve6(options.output) : join7(backupDir, options.preUpdate ? `latest-pre-update-${role}.tar.gz` : `openmates-${role}-${nowStamp()}.tar.gz`);
|
|
29328
|
+
mkdirSync6(dirname6(archivePath), { recursive: true, mode: 448 });
|
|
29299
29329
|
const tempDir = mkdtempSync(join7(backupDir, ".tmp-"));
|
|
29300
29330
|
const env = readEnvMap(installPath);
|
|
29301
29331
|
const manifest = {
|
|
29302
29332
|
role,
|
|
29333
|
+
backup_format_version: BACKUP_FORMAT_VERSION,
|
|
29303
29334
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29304
29335
|
cli_version: getPackageVersion(),
|
|
29305
29336
|
image_tag: getEnvVar(existsSync9(join7(installPath, ".env")) ? readFileSync7(join7(installPath, ".env"), "utf-8") : "", "OPENMATES_IMAGE_TAG"),
|
|
29306
|
-
|
|
29307
|
-
|
|
29337
|
+
recovery_scope: role === "core" ? "database-and-runtime-only" : "runtime-only",
|
|
29338
|
+
include_observability: false,
|
|
29339
|
+
contents: plan.contents.filter((content) => content !== "runtime-env" || existsSync9(join7(installPath, ".env"))).filter((content) => content !== "runtime-config" || existsSync9(join7(installPath, "config")))
|
|
29308
29340
|
};
|
|
29309
29341
|
try {
|
|
29310
|
-
writeFileSync5(join7(tempDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
29311
|
-
`);
|
|
29312
29342
|
copyIfExists(join7(installPath, ".env"), join7(tempDir, "runtime", ".env"));
|
|
29313
29343
|
copyIfExists(join7(installPath, "config"), join7(tempDir, "runtime", "config"));
|
|
29314
29344
|
if (role === "core") {
|
|
@@ -29329,19 +29359,13 @@ function createServerBackup(installPath, role, options = {}) {
|
|
|
29329
29359
|
closeSync2(dumpFile);
|
|
29330
29360
|
}
|
|
29331
29361
|
}
|
|
29332
|
-
|
|
29333
|
-
|
|
29334
|
-
[join7(installPath, "backend", "core", "extensions"), join7(tempDir, "directus-extensions")],
|
|
29335
|
-
[join7(installPath, "backend", role, "vault"), join7(tempDir, `${role}-vault-config`)]
|
|
29336
|
-
]) {
|
|
29337
|
-
copyIfExists(item[0], item[1]);
|
|
29338
|
-
}
|
|
29362
|
+
writeFileSync5(join7(tempDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
29363
|
+
`, { mode: 384 });
|
|
29339
29364
|
writeChecksums(tempDir);
|
|
29340
|
-
|
|
29341
|
-
chmodSync4(archivePath, plan.fileMode);
|
|
29365
|
+
publishServerBackupArchive(tempDir, archivePath);
|
|
29342
29366
|
return archivePath;
|
|
29343
29367
|
} finally {
|
|
29344
|
-
|
|
29368
|
+
rmSync6(tempDir, { recursive: true, force: true });
|
|
29345
29369
|
}
|
|
29346
29370
|
}
|
|
29347
29371
|
function restoreServerBackup(installPath, role, file) {
|
|
@@ -29357,19 +29381,30 @@ function restoreServerBackup(installPath, role, file) {
|
|
|
29357
29381
|
if (!existsSync9(manifestPath)) throw new Error("Backup archive is missing manifest.json.");
|
|
29358
29382
|
const manifest = JSON.parse(readFileSync7(manifestPath, "utf-8"));
|
|
29359
29383
|
if (manifest.role !== role) throw new Error(`Backup role '${manifest.role}' does not match requested role '${role}'.`);
|
|
29384
|
+
if (role === "core" && manifest.backup_format_version === BACKUP_FORMAT_VERSION && manifest.recovery_scope !== "full-core") {
|
|
29385
|
+
throw new Error("This backup records database and runtime state only; refusing unsafe full core restore.");
|
|
29386
|
+
}
|
|
29360
29387
|
copyIfExists(join7(tempDir, "runtime", ".env"), join7(installPath, ".env"));
|
|
29361
29388
|
copyIfExists(join7(tempDir, "runtime", "config"), join7(installPath, "config"));
|
|
29362
29389
|
const postgresDump = join7(tempDir, "postgres.sql");
|
|
29363
29390
|
if (role === "core" && existsSync9(postgresDump)) {
|
|
29364
29391
|
const databaseUser = env.DATABASE_USERNAME || "directus";
|
|
29365
29392
|
const databaseName = env.DATABASE_NAME || "directus";
|
|
29366
|
-
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29393
|
+
const dumpFile = openSync2(postgresDump, "r");
|
|
29394
|
+
try {
|
|
29395
|
+
const result = spawnSync(
|
|
29396
|
+
"docker",
|
|
29397
|
+
["exec", "-i", "cms-database", "psql", "-v", "ON_ERROR_STOP=1", "-U", databaseUser, databaseName],
|
|
29398
|
+
{ encoding: "utf-8", stdio: [dumpFile, "pipe", "pipe"] }
|
|
29399
|
+
);
|
|
29400
|
+
if (result.error) throw result.error;
|
|
29401
|
+
if (result.status !== 0) throw new Error(result.stderr || `psql exited with status ${result.status}`);
|
|
29402
|
+
} finally {
|
|
29403
|
+
closeSync2(dumpFile);
|
|
29404
|
+
}
|
|
29370
29405
|
}
|
|
29371
29406
|
} finally {
|
|
29372
|
-
|
|
29407
|
+
rmSync6(tempDir, { recursive: true, force: true });
|
|
29373
29408
|
}
|
|
29374
29409
|
}
|
|
29375
29410
|
function restoreStopServices(installPath, withOverrides, installMode, role) {
|
|
@@ -29992,7 +30027,7 @@ async function runUpdateCompletionEmailGate(input) {
|
|
|
29992
30027
|
deliveryId: deliveryPlan.deliveryId
|
|
29993
30028
|
};
|
|
29994
30029
|
}
|
|
29995
|
-
const deliveryId = deliveryPlan.deliveryId ??
|
|
30030
|
+
const deliveryId = deliveryPlan.deliveryId ?? randomUUID11();
|
|
29996
30031
|
const deliveryPendingAt = deliveryPlan.pendingAt ?? completedAt;
|
|
29997
30032
|
const previousAttempts = deliveryPlan.previousAttempts ?? 0;
|
|
29998
30033
|
const { role: _role, updated_at: _updatedAt, ...currentStatus } = readServerUpdateStatus(input.installPath, input.role);
|
|
@@ -30131,18 +30166,18 @@ async function installRuntimeMonitoringServices(installPath, role) {
|
|
|
30131
30166
|
const installedOperationalUnits = operationalUnitNames.filter((name) => existsSync9(join7("/etc", "systemd", "system", name)));
|
|
30132
30167
|
const installedOperationalTimers = installedOperationalUnits.filter((name) => name.endsWith(".timer"));
|
|
30133
30168
|
if (installedOperationalTimers.length) {
|
|
30134
|
-
|
|
30169
|
+
execFileSync4("systemctl", ["disable", "--now", ...installedOperationalTimers], { stdio: "pipe" });
|
|
30135
30170
|
}
|
|
30136
|
-
for (const name of installedOperationalUnits)
|
|
30171
|
+
for (const name of installedOperationalUnits) rmSync6(join7("/etc", "systemd", "system", name));
|
|
30137
30172
|
for (const path2 of [reportStatePath, startedMetricPath, successMetricPath]) {
|
|
30138
|
-
if (existsSync9(path2))
|
|
30173
|
+
if (existsSync9(path2)) rmSync6(path2);
|
|
30139
30174
|
}
|
|
30140
30175
|
}
|
|
30141
30176
|
for (const [name, content] of files) writeFileSync5(join7("/etc", "systemd", "system", name), content, { mode: 420 });
|
|
30142
30177
|
execSync("systemctl daemon-reload", { stdio: "pipe" });
|
|
30143
30178
|
const timers = files.filter(([name]) => name.endsWith(".timer")).map(([name]) => name);
|
|
30144
30179
|
execSync(`systemctl enable --now ${timers.map(shellQuote).join(" ")}`, { stdio: "pipe" });
|
|
30145
|
-
for (const timer of timers)
|
|
30180
|
+
for (const timer of timers) execFileSync4("systemctl", ["is-active", "--quiet", timer], { stdio: "pipe" });
|
|
30146
30181
|
}
|
|
30147
30182
|
async function autoInstallRuntimeMonitoringServices(installPath, role) {
|
|
30148
30183
|
if (!shouldAutoInstallRuntimeMonitoringServices(process.env)) {
|
|
@@ -31145,7 +31180,7 @@ async function serverBackup(rest, flags) {
|
|
|
31145
31180
|
const role = getServerRole(flags, config);
|
|
31146
31181
|
if (action === "list") {
|
|
31147
31182
|
const dir = roleBackupDir(installPath, role);
|
|
31148
|
-
const files = existsSync9(dir) ?
|
|
31183
|
+
const files = existsSync9(dir) ? readdirSync4(dir).filter((item) => item.endsWith(".tar.gz")).sort() : [];
|
|
31149
31184
|
if (flags.json === true) {
|
|
31150
31185
|
printJson({ role, backupDir: dir, files });
|
|
31151
31186
|
return;
|
|
@@ -31240,7 +31275,7 @@ async function serverUninstall(flags) {
|
|
|
31240
31275
|
} catch {
|
|
31241
31276
|
}
|
|
31242
31277
|
try {
|
|
31243
|
-
|
|
31278
|
+
rmSync6(installPath, { recursive: true, force: true });
|
|
31244
31279
|
console.error(` Removed installation directory: ${installPath}`);
|
|
31245
31280
|
} catch (e) {
|
|
31246
31281
|
console.error(` Could not remove ${installPath}: ${e instanceof Error ? e.message : e}`);
|
|
@@ -70488,8 +70523,8 @@ function buildAssistantFeedbackDecision(rating) {
|
|
|
70488
70523
|
}
|
|
70489
70524
|
|
|
70490
70525
|
// src/benchmark.ts
|
|
70491
|
-
import { createHash as createHash13, randomUUID as
|
|
70492
|
-
import { existsSync as existsSync10, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, readdirSync as
|
|
70526
|
+
import { createHash as createHash13, randomUUID as randomUUID12 } from "crypto";
|
|
70527
|
+
import { existsSync as existsSync10, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, readdirSync as readdirSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
70493
70528
|
import { tmpdir } from "os";
|
|
70494
70529
|
import { dirname as dirname7, join as join8, resolve as resolve8 } from "path";
|
|
70495
70530
|
import { fileURLToPath } from "url";
|
|
@@ -70904,7 +70939,7 @@ async function handleBenchmark(client, subcommand, rest, flags) {
|
|
|
70904
70939
|
const caseIds = parseCaseIds(flags.case);
|
|
70905
70940
|
const dryRun = flags["dry-run"] === true;
|
|
70906
70941
|
const output = typeof flags.output === "string" ? flags.output : void 0;
|
|
70907
|
-
const runId = typeof flags["run-id"] === "string" ? flags["run-id"] :
|
|
70942
|
+
const runId = typeof flags["run-id"] === "string" ? flags["run-id"] : randomUUID12();
|
|
70908
70943
|
const imagePath = typeof flags.image === "string" ? resolve8(flags.image) : defaultImageFixturePath();
|
|
70909
70944
|
if (!dryRun && flags["confirm-spend-credits"] !== true) {
|
|
70910
70945
|
throw new Error(
|
|
@@ -71006,7 +71041,7 @@ async function handlePromptBudgetBenchmark(client, rest, flags) {
|
|
|
71006
71041
|
if (resumeArtifact) {
|
|
71007
71042
|
validatePromptBudgetResumeArtifact(resumeArtifact, { phase, targetModel, judgeModel });
|
|
71008
71043
|
}
|
|
71009
|
-
const runId = stringFlag(flags["run-id"]) ?? resumeArtifact?.runId ??
|
|
71044
|
+
const runId = stringFlag(flags["run-id"]) ?? resumeArtifact?.runId ?? randomUUID12();
|
|
71010
71045
|
const result = makePromptBudgetBaseResult({
|
|
71011
71046
|
phase,
|
|
71012
71047
|
runId,
|
|
@@ -71567,7 +71602,7 @@ function buildLongContextHistory() {
|
|
|
71567
71602
|
}
|
|
71568
71603
|
function appendHistory(history, role, content) {
|
|
71569
71604
|
history.push({
|
|
71570
|
-
message_id:
|
|
71605
|
+
message_id: randomUUID12(),
|
|
71571
71606
|
role,
|
|
71572
71607
|
sender_name: role === "user" ? "User" : "Assistant",
|
|
71573
71608
|
content,
|
|
@@ -71657,7 +71692,7 @@ function loadProviderPricing() {
|
|
|
71657
71692
|
const providersDir = findProvidersDir();
|
|
71658
71693
|
const pricing = /* @__PURE__ */ new Map();
|
|
71659
71694
|
if (!providersDir) return pricing;
|
|
71660
|
-
for (const fileName of
|
|
71695
|
+
for (const fileName of readdirSync5(providersDir)) {
|
|
71661
71696
|
if (!fileName.endsWith(".yml")) continue;
|
|
71662
71697
|
const filePath = join8(providersDir, fileName);
|
|
71663
71698
|
const text = readFileSync8(filePath, "utf-8");
|
|
@@ -73434,7 +73469,7 @@ function clamp(value, min, max) {
|
|
|
73434
73469
|
// src/remoteAccess.ts
|
|
73435
73470
|
import { homedir as homedir7 } from "os";
|
|
73436
73471
|
import {
|
|
73437
|
-
chmodSync as
|
|
73472
|
+
chmodSync as chmodSync6,
|
|
73438
73473
|
closeSync as closeSync3,
|
|
73439
73474
|
constants,
|
|
73440
73475
|
existsSync as existsSync11,
|
|
@@ -73442,7 +73477,7 @@ import {
|
|
|
73442
73477
|
mkdirSync as mkdirSync7,
|
|
73443
73478
|
openSync as openSync3,
|
|
73444
73479
|
readFileSync as readFileSync9,
|
|
73445
|
-
readdirSync as
|
|
73480
|
+
readdirSync as readdirSync6,
|
|
73446
73481
|
readSync as readSync2,
|
|
73447
73482
|
realpathSync,
|
|
73448
73483
|
statSync as statSync2,
|
|
@@ -73586,7 +73621,7 @@ function discoverRemoteAccessRepositories(roots) {
|
|
|
73586
73621
|
const visit = (directory, approvedRoot) => {
|
|
73587
73622
|
let entries;
|
|
73588
73623
|
try {
|
|
73589
|
-
entries =
|
|
73624
|
+
entries = readdirSync6(directory, { withFileTypes: true });
|
|
73590
73625
|
} catch (error) {
|
|
73591
73626
|
const code = error.code;
|
|
73592
73627
|
if (code === "EACCES" || code === "EPERM") {
|
|
@@ -73624,7 +73659,7 @@ function listRemoteAccessDirectory(options) {
|
|
|
73624
73659
|
const entries = [];
|
|
73625
73660
|
let omitted = 0;
|
|
73626
73661
|
let excluded = 0;
|
|
73627
|
-
for (const entry of
|
|
73662
|
+
for (const entry of readdirSync6(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
73628
73663
|
const entryPath = relative2(root, join9(directory, entry.name)).replace(/\\/g, "/");
|
|
73629
73664
|
if (entry.name === ".git" || entry.isSymbolicLink() || isGitIgnoredPath(root, entryPath) || classifyProjectFileRisk(entryPath, options.userProtectedPatterns ?? []).isHighRisk || entry.isFile() && isBinaryFile(join9(directory, entry.name))) {
|
|
73630
73665
|
excluded += 1;
|
|
@@ -73972,7 +74007,7 @@ function searchRemoteSourceWithoutRg(query, sourceRoot, maxResults, userProtecte
|
|
|
73972
74007
|
const directory = directories.pop();
|
|
73973
74008
|
let entries;
|
|
73974
74009
|
try {
|
|
73975
|
-
entries =
|
|
74010
|
+
entries = readdirSync6(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
73976
74011
|
} catch {
|
|
73977
74012
|
excluded += 1;
|
|
73978
74013
|
continue;
|
|
@@ -74185,10 +74220,10 @@ function saveRemoteAccessSources(sources, homeDirectory) {
|
|
|
74185
74220
|
const filePath = remoteAccessStorePath(homeDirectory);
|
|
74186
74221
|
const stateDir2 = join9(homeDirectory, ".openmates");
|
|
74187
74222
|
mkdirSync7(stateDir2, { recursive: true, mode: 448 });
|
|
74188
|
-
|
|
74223
|
+
chmodSync6(stateDir2, 448);
|
|
74189
74224
|
writeFileSync7(filePath, `${JSON.stringify({ sources }, null, 2)}
|
|
74190
74225
|
`, { mode: 384 });
|
|
74191
|
-
|
|
74226
|
+
chmodSync6(filePath, 384);
|
|
74192
74227
|
}
|
|
74193
74228
|
function assertRemoteAccessSourceRecord(value, index) {
|
|
74194
74229
|
if (typeof value !== "object" || value === null) {
|
|
@@ -74206,7 +74241,7 @@ function assertRemoteAccessSourceRecord(value, index) {
|
|
|
74206
74241
|
}
|
|
74207
74242
|
|
|
74208
74243
|
// src/projectRequester.ts
|
|
74209
|
-
import { randomUUID as
|
|
74244
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
74210
74245
|
var REMOTE_PROTOCOL_TIMEOUT_MS = 45e3;
|
|
74211
74246
|
var REMOTE_POLL_INTERVAL_MS = 250;
|
|
74212
74247
|
var MAX_REMOTE_RESULT_BYTES = 200 * 1024;
|
|
@@ -74232,8 +74267,8 @@ async function requestProjectRemoteOperation(options) {
|
|
|
74232
74267
|
keyEpoch = discovery.keyEpoch;
|
|
74233
74268
|
routingIdentity = discovery.routingIdentity;
|
|
74234
74269
|
}
|
|
74235
|
-
const requestingClientId =
|
|
74236
|
-
const requestId =
|
|
74270
|
+
const requestingClientId = randomUUID13();
|
|
74271
|
+
const requestId = randomUUID13();
|
|
74237
74272
|
const identity = await buildIdentity(
|
|
74238
74273
|
options.client,
|
|
74239
74274
|
options.projectId,
|
|
@@ -74294,9 +74329,9 @@ async function requestProjectRemoteOperation(options) {
|
|
|
74294
74329
|
return response.result;
|
|
74295
74330
|
}
|
|
74296
74331
|
async function discoverRouting(options, timeoutMs) {
|
|
74297
|
-
const requestId =
|
|
74298
|
-
const requestingClientId =
|
|
74299
|
-
const nonce =
|
|
74332
|
+
const requestId = randomUUID13();
|
|
74333
|
+
const requestingClientId = randomUUID13();
|
|
74334
|
+
const nonce = randomUUID13();
|
|
74300
74335
|
const encryptedEnvelope = await encryptWithAesGcmCombined(JSON.stringify({
|
|
74301
74336
|
type: "routing_discovery",
|
|
74302
74337
|
requesting_client_id: requestingClientId,
|
|
@@ -74507,7 +74542,7 @@ function commandName(name) {
|
|
|
74507
74542
|
}
|
|
74508
74543
|
|
|
74509
74544
|
// src/workRecovery.ts
|
|
74510
|
-
import { mkdirSync as mkdirSync8, renameSync as
|
|
74545
|
+
import { mkdirSync as mkdirSync8, renameSync as renameSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
74511
74546
|
import { dirname as dirname8 } from "path";
|
|
74512
74547
|
import { stringify } from "yaml";
|
|
74513
74548
|
async function projectPlanAssumption(plan, masterKey, assumption) {
|
|
@@ -74690,13 +74725,13 @@ function writeWorkRecoveryAtomically(path2, document) {
|
|
|
74690
74725
|
mkdirSync8(dirname8(path2), { recursive: true, mode: 448 });
|
|
74691
74726
|
const temporaryPath = `${path2}.tmp`;
|
|
74692
74727
|
writeFileSync8(temporaryPath, stringify(document, { sortMapEntries: true, lineWidth: 0 }), { encoding: "utf8", mode: 384 });
|
|
74693
|
-
|
|
74728
|
+
renameSync3(temporaryPath, path2);
|
|
74694
74729
|
}
|
|
74695
74730
|
|
|
74696
74731
|
// src/revolutBusinessCertificate.ts
|
|
74697
|
-
import { execFileSync as
|
|
74698
|
-
import { createSign, randomUUID as
|
|
74699
|
-
import { chmodSync as
|
|
74732
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
74733
|
+
import { createSign, randomUUID as randomUUID14 } from "crypto";
|
|
74734
|
+
import { chmodSync as chmodSync7, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync11 } from "fs";
|
|
74700
74735
|
import { homedir as homedir8 } from "os";
|
|
74701
74736
|
import { join as join10, resolve as resolve10 } from "path";
|
|
74702
74737
|
var REVOLUT_BUSINESS_CERTIFICATE_DOCS_URL = "https://developer.revolut.com/docs/guides/manage-accounts/get-started/make-your-first-api-request#generate-a-private-and-a-public-certificate";
|
|
@@ -74769,7 +74804,7 @@ function generateRevolutBusinessClientAssertion(options) {
|
|
|
74769
74804
|
aud: REVOLUT_BUSINESS_AUDIENCE,
|
|
74770
74805
|
exp: now + 3600,
|
|
74771
74806
|
iat: now,
|
|
74772
|
-
jti:
|
|
74807
|
+
jti: randomUUID14()
|
|
74773
74808
|
});
|
|
74774
74809
|
const unsigned = `${header2}.${payload}`;
|
|
74775
74810
|
const signer = createSign("RSA-SHA256");
|
|
@@ -74785,16 +74820,16 @@ function generateRevolutBusinessCertificate(options = {}) {
|
|
|
74785
74820
|
if (!title) throw new Error("Revolut certificate title must not be empty.");
|
|
74786
74821
|
if (!redirectUri.startsWith("https://")) throw new Error("Revolut OAuth redirect URI must start with https://.");
|
|
74787
74822
|
mkdirSync9(outputDir, { recursive: true, mode: 448 });
|
|
74788
|
-
|
|
74823
|
+
chmodSync7(outputDir, 448);
|
|
74789
74824
|
const privateKeyPath = join10(outputDir, "privatecert.pem");
|
|
74790
74825
|
const publicCertificatePath = join10(outputDir, "publiccert.cer");
|
|
74791
74826
|
if (!options.overwrite && (existsSync12(privateKeyPath) || existsSync12(publicCertificatePath))) {
|
|
74792
74827
|
throw new Error(`Revolut certificate files already exist in ${outputDir}. Re-run with --overwrite to replace them.`);
|
|
74793
74828
|
}
|
|
74794
74829
|
try {
|
|
74795
|
-
|
|
74796
|
-
|
|
74797
|
-
|
|
74830
|
+
execFileSync5("openssl", ["genrsa", "-out", privateKeyPath, RSA_BITS], { stdio: "ignore" });
|
|
74831
|
+
chmodSync7(privateKeyPath, 384);
|
|
74832
|
+
execFileSync5(
|
|
74798
74833
|
"openssl",
|
|
74799
74834
|
[
|
|
74800
74835
|
"req",
|
|
@@ -76081,7 +76116,7 @@ async function resolveAddToProjectStorageChoice(client, project, flags, objectTy
|
|
|
76081
76116
|
async function createEncryptedProjectItem(client, project, input) {
|
|
76082
76117
|
const timestamp = nowSeconds3();
|
|
76083
76118
|
return client.createProjectItem(project.projectId, {
|
|
76084
|
-
project_item_id:
|
|
76119
|
+
project_item_id: randomUUID15(),
|
|
76085
76120
|
folder_id: input.folderId ?? null,
|
|
76086
76121
|
item_type: input.itemType,
|
|
76087
76122
|
target_id: input.targetId,
|
|
@@ -76275,7 +76310,7 @@ async function handlePlans(client, subcommand, rest, flags, redactor) {
|
|
|
76275
76310
|
const encryptedSources = proof.length ? await encryptPlanAssumptionSources(plan, masterKey, proof) : void 0;
|
|
76276
76311
|
if (action === "create" || action === "add") {
|
|
76277
76312
|
const assumption = await client.createPlanAssumption(plan.planId, {
|
|
76278
|
-
assumption_id: typeof flags.id === "string" ? flags.id :
|
|
76313
|
+
assumption_id: typeof flags.id === "string" ? flags.id : randomUUID15(),
|
|
76279
76314
|
encrypted_text: await encryptPlanAssumptionSources(plan, masterKey, requiredStringFlag(flags.text ?? rest.slice(2).join(" "), "--text <assumption>")),
|
|
76280
76315
|
status: typeof flags.status === "string" ? flags.status : void 0,
|
|
76281
76316
|
linked_sub_chat_id: typeof flags["sub-chat"] === "string" ? flags["sub-chat"] : void 0,
|
|
@@ -77200,7 +77235,7 @@ async function handleProjects(client, subcommand, rest, flags, redactor) {
|
|
|
77200
77235
|
const name = requiredStringFlag(rest[0] ?? flags.name, "project name");
|
|
77201
77236
|
const projectKey = randomBytes9(32);
|
|
77202
77237
|
const wrapping = await client.projectWrappingKey(context);
|
|
77203
|
-
const projectId =
|
|
77238
|
+
const projectId = randomUUID15();
|
|
77204
77239
|
const timestamp = nowSeconds3();
|
|
77205
77240
|
const slugMetadata = await buildEncryptedObjectSlugMetadata({
|
|
77206
77241
|
value: typeof flags.slug === "string" ? flags.slug : name,
|
|
@@ -77308,7 +77343,7 @@ async function handleProjects(client, subcommand, rest, flags, redactor) {
|
|
|
77308
77343
|
const proposal = isShortWorkspaceAsk(instruction) ? { name: instruction, description: "", icon: "folder", color: "default" } : extractRecord(await client.planProjectAsk({ instruction }), "proposed_project");
|
|
77309
77344
|
const projectKey = randomBytes9(32);
|
|
77310
77345
|
const timestamp = Math.floor(Date.now() / 1e3);
|
|
77311
|
-
const projectId =
|
|
77346
|
+
const projectId = randomUUID15();
|
|
77312
77347
|
const name = requiredString(proposal, "name", instruction);
|
|
77313
77348
|
const slugMetadata = await buildEncryptedObjectSlugMetadata({
|
|
77314
77349
|
value: typeof flags.slug === "string" ? flags.slug : name,
|
|
@@ -78207,7 +78242,7 @@ async function handleRemoteAccess(client, subcommand, rest, flags) {
|
|
|
78207
78242
|
const projects = await loadProjects(client, masterKey, hostingFlags, hostingContext);
|
|
78208
78243
|
const bindings = await resolveRemoteAccessBindings(client, masterKey, projects, candidateRoots, hostingFlags, hostingContext);
|
|
78209
78244
|
if (bindings.length === 0) throw new Error("No Project folders were approved for remote access.");
|
|
78210
|
-
const sourceSessionId =
|
|
78245
|
+
const sourceSessionId = randomUUID15();
|
|
78211
78246
|
const controller = new AbortController();
|
|
78212
78247
|
const stop = () => controller.abort();
|
|
78213
78248
|
process.once("SIGINT", stop);
|
|
@@ -78315,7 +78350,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
|
|
|
78315
78350
|
if (answer !== "y" && answer !== "yes") throw new Error("Remote access Project creation cancelled.");
|
|
78316
78351
|
for (const rootPath of unresolved) {
|
|
78317
78352
|
const project = await createEncryptedRemoteAccessProject(client, masterKey, basename3(rootPath), context);
|
|
78318
|
-
resolved.push({ rootPath, project, sourceId:
|
|
78353
|
+
resolved.push({ rootPath, project, sourceId: randomUUID15() });
|
|
78319
78354
|
}
|
|
78320
78355
|
}
|
|
78321
78356
|
const bindings = [];
|
|
@@ -78352,7 +78387,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
|
|
|
78352
78387
|
}
|
|
78353
78388
|
async function createEncryptedRemoteAccessProject(client, masterKey, name, context) {
|
|
78354
78389
|
const projectKey = randomBytes9(32);
|
|
78355
|
-
const projectId =
|
|
78390
|
+
const projectId = randomUUID15();
|
|
78356
78391
|
const timestamp = Math.floor(Date.now() / 1e3);
|
|
78357
78392
|
const wrapping = await client.projectWrappingKey(context);
|
|
78358
78393
|
const payload = {
|
|
@@ -81650,7 +81685,7 @@ async function runAccountImport(client, parserFormat, file, flags) {
|
|
|
81650
81685
|
if (flags.yes !== true) {
|
|
81651
81686
|
await confirmOrExit(`Import ${selectedCount} chat(s) into new encrypted OpenMates chats? [y/N] `);
|
|
81652
81687
|
}
|
|
81653
|
-
const importId = typeof preview.import_id === "string" ? preview.import_id :
|
|
81688
|
+
const importId = typeof preview.import_id === "string" ? preview.import_id : randomUUID15();
|
|
81654
81689
|
const selectedChats = parsed.chats.slice(0, selectedCount);
|
|
81655
81690
|
const selectedFingerprints = selectedChats.map((chat) => chat.source_fingerprint);
|
|
81656
81691
|
const confirmation = await client.confirmAccountImport(importId, selectedFingerprints);
|
|
@@ -82144,8 +82179,8 @@ async function handleFinance(client, subcommand, _rest, flags) {
|
|
|
82144
82179
|
refresh_token_envelope: connectedAccount.refreshTokenBundle
|
|
82145
82180
|
}
|
|
82146
82181
|
] : [],
|
|
82147
|
-
chatId: `cli-finance-${
|
|
82148
|
-
messageId: `cli-finance-message-${
|
|
82182
|
+
chatId: `cli-finance-${randomUUID15()}`,
|
|
82183
|
+
messageId: `cli-finance-message-${randomUUID15()}`,
|
|
82149
82184
|
apiKey: resolveApiKey(flags) ?? void 0,
|
|
82150
82185
|
promptInjectionProtection: false
|
|
82151
82186
|
});
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED