openmates 0.18.0-alpha.1 → 0.18.0-alpha.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.
@@ -20131,12 +20131,12 @@ var ACCOUNT_EXPORT_FORBIDDEN_VALUE_PATTERNS = [
20131
20131
  ];
20132
20132
  async function writeAccountExportArchive(bundle, flags = {}) {
20133
20133
  const { mkdir: mkdir2, writeFile: writeFile2 } = await import("fs/promises");
20134
- const { join: join11, dirname: dirname10 } = await import("path");
20134
+ const { join: join12, dirname: dirname11 } = await import("path");
20135
20135
  const exportId = safeArchiveSegment(String(bundle.export.export_id ?? `export-${Date.now()}`));
20136
20136
  const archiveFormat = flags.format === "directory" ? "directory" : "zip";
20137
20137
  const password = typeof flags.password === "string" && flags.password.length > 0 ? flags.password : null;
20138
20138
  if (password && archiveFormat !== "zip") throw new Error("Password-protected account export is only supported for zip format.");
20139
- const outputPath = typeof flags.output === "string" ? flags.output : join11(process.cwd(), archiveFormat === "zip" ? `openmates-account-export-${exportId}${password ? ".zip.enc" : ".zip"}` : `openmates-account-export-${exportId}`);
20139
+ const outputPath = typeof flags.output === "string" ? flags.output : join12(process.cwd(), archiveFormat === "zip" ? `openmates-account-export-${exportId}${password ? ".zip.enc" : ".zip"}` : `openmates-account-export-${exportId}`);
20140
20140
  const zip = archiveFormat === "zip" ? new JSZip3() : null;
20141
20141
  const writtenFiles = [];
20142
20142
  async function writeArchiveText(relativePath, content) {
@@ -20147,8 +20147,8 @@ async function writeAccountExportArchive(bundle, flags = {}) {
20147
20147
  return;
20148
20148
  }
20149
20149
  const stagingDir = outputPath;
20150
- const fullPath = join11(stagingDir, relativePath);
20151
- await mkdir2(dirname10(fullPath), { recursive: true });
20150
+ const fullPath = join12(stagingDir, relativePath);
20151
+ await mkdir2(dirname11(fullPath), { recursive: true });
20152
20152
  await writeFile2(fullPath, content, "utf-8");
20153
20153
  writtenFiles.push(relativePath);
20154
20154
  }
@@ -20165,7 +20165,7 @@ async function writeAccountExportArchive(bundle, flags = {}) {
20165
20165
  }
20166
20166
  await writeAccountExportChatFiles(domainPayloads.chats ?? [], writeArchiveText);
20167
20167
  if (archiveFormat === "directory") return { output: outputPath, format: "directory", files: writtenFiles.length };
20168
- await mkdir2(dirname10(outputPath), { recursive: true });
20168
+ await mkdir2(dirname11(outputPath), { recursive: true });
20169
20169
  const zipBuffer = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
20170
20170
  await writeFile2(outputPath, password ? encryptZipBuffer(zipBuffer, password) : zipBuffer);
20171
20171
  return { output: outputPath, format: "zip", files: writtenFiles.length, ...password ? { encrypted: true } : {} };
@@ -24298,10 +24298,10 @@ var OpenMatesBenchmark = class {
24298
24298
  // src/cli.ts
24299
24299
  import { createInterface as createInterface5 } from "readline/promises";
24300
24300
  import { stdin as stdin3, stdout as stdout2 } from "process";
24301
- import { existsSync as existsSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, writeFileSync as writeFileSync9 } from "fs";
24302
- import { fileURLToPath as fileURLToPath2 } from "url";
24303
- import { basename as basename3, dirname as dirname9 } from "path";
24304
- import { createHash as createHash14, randomBytes as randomBytes9, randomUUID as randomUUID14 } from "crypto";
24301
+ import { existsSync as existsSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, writeFileSync as writeFileSync10 } from "fs";
24302
+ import { fileURLToPath as fileURLToPath3 } from "url";
24303
+ import { basename as basename4, dirname as dirname10 } from "path";
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 execFileSync3, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
26483
- import { createHash as createHash12, randomBytes as randomBytes8, randomUUID as randomUUID10 } from "crypto";
26484
- import { appendFileSync, chmodSync as chmodSync4, closeSync as closeSync2, copyFileSync as copyFileSync2, cpSync, existsSync as existsSync9, mkdirSync as mkdirSync6, mkdtempSync, openSync as openSync2, readFileSync as readFileSync7, readSync, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
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", "directus-uploads", "directus-extensions", "vault-data", "vault-setup-data", "runtime-env", "runtime-config", "manifest", "checksums"],
26959
- upload: ["vault-data", "vault-setup-data", "runtime-env", "runtime-config", "manifest", "checksums"],
26960
- preview: ["runtime-env", "runtime-config", "preview-cache", "manifest", "checksums"]
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 randomUUID8 } from "crypto";
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 = randomUUID8();
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 chmodSync3, closeSync, existsSync as existsSync8, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync6, renameSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
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
- renameSync(temporaryPath, filePath);
27815
- chmodSync3(filePath, 384);
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
- rmSync4(lockPath);
27870
+ rmSync5(lockPath);
27843
27871
  }
27844
27872
  };
27845
27873
  }
27846
27874
 
27847
27875
  // src/serverQuickTest.ts
27848
- import { randomUUID as randomUUID9 } from "crypto";
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 = randomUUID9();
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 = execFileSync3("python3", args, {
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
- execFileSync3(
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 = execFileSync3(
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(execFileSync3(
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 = readdirSync3(installPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.startsWith(ENV_BACKUP_PREFIX)).map((entry) => entry.name).sort();
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
- rmSync5(join7(installPath, backup), { force: true });
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
- chmodSync4(backupPath, 384);
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
- chmodSync4(envPath, 384);
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 = execFileSync3(
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 readdirSync3(dir, { withFileTypes: true })) {
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
- include_observability: options.includeObservability === true,
29307
- contents: plan.contents
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
- for (const item of [
29333
- [join7(installPath, "backend", "core", "uploads"), join7(tempDir, "directus-uploads")],
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
- execSync(`tar -czf ${shellQuote(archivePath)} -C ${shellQuote(tempDir)} .`, { stdio: "pipe" });
29341
- chmodSync4(archivePath, plan.fileMode);
29365
+ publishServerBackupArchive(tempDir, archivePath);
29342
29366
  return archivePath;
29343
29367
  } finally {
29344
- rmSync5(tempDir, { recursive: true, force: true });
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
- execSync(`docker exec -i cms-database psql -v ON_ERROR_STOP=1 -U ${shellQuote(databaseUser)} ${shellQuote(databaseName)}`, {
29367
- input: readFileSync7(postgresDump),
29368
- stdio: ["pipe", "pipe", "pipe"]
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
- rmSync5(tempDir, { recursive: true, force: true });
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 ?? randomUUID10();
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
- execFileSync3("systemctl", ["disable", "--now", ...installedOperationalTimers], { stdio: "pipe" });
30169
+ execFileSync4("systemctl", ["disable", "--now", ...installedOperationalTimers], { stdio: "pipe" });
30135
30170
  }
30136
- for (const name of installedOperationalUnits) rmSync5(join7("/etc", "systemd", "system", name));
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)) rmSync5(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) execFileSync3("systemctl", ["is-active", "--quiet", timer], { stdio: "pipe" });
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) ? readdirSync3(dir).filter((item) => item.endsWith(".tar.gz")).sort() : [];
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
- rmSync5(installPath, { recursive: true, force: true });
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}`);
@@ -48913,9 +48948,9 @@ function basenameFromUrl(url) {
48913
48948
  return withoutQuery.split("/").pop()?.replace(/[^a-zA-Z0-9._-]/g, "_") ?? "";
48914
48949
  }
48915
48950
  function extensionFromUrl(url) {
48916
- const basename4 = basenameFromUrl(url);
48917
- const dotIndex = basename4.lastIndexOf(".");
48918
- return dotIndex > 0 ? basename4.slice(dotIndex + 1).toLowerCase() : "";
48951
+ const basename5 = basenameFromUrl(url);
48952
+ const dotIndex = basename5.lastIndexOf(".");
48953
+ return dotIndex > 0 ? basename5.slice(dotIndex + 1).toLowerCase() : "";
48919
48954
  }
48920
48955
  function extensionFromLanguage(language) {
48921
48956
  const normalized = language.toLowerCase();
@@ -70488,8 +70523,8 @@ function buildAssistantFeedbackDecision(rating) {
70488
70523
  }
70489
70524
 
70490
70525
  // src/benchmark.ts
70491
- import { createHash as createHash13, randomUUID as randomUUID11 } from "crypto";
70492
- import { existsSync as existsSync10, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, readdirSync as readdirSync4, writeFileSync as writeFileSync6 } from "fs";
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"] : randomUUID11();
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 ?? randomUUID11();
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: randomUUID11(),
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 readdirSync4(providersDir)) {
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 chmodSync5,
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 readdirSync5,
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 = readdirSync5(directory, { withFileTypes: true });
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 readdirSync5(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
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 = readdirSync5(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
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
- chmodSync5(stateDir2, 448);
74223
+ chmodSync6(stateDir2, 448);
74189
74224
  writeFileSync7(filePath, `${JSON.stringify({ sources }, null, 2)}
74190
74225
  `, { mode: 384 });
74191
- chmodSync5(filePath, 384);
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 randomUUID12 } from "crypto";
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 = randomUUID12();
74236
- const requestId = randomUUID12();
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 = randomUUID12();
74298
- const requestingClientId = randomUUID12();
74299
- const nonce = randomUUID12();
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,
@@ -74394,9 +74429,64 @@ function remoteErrorMessage(code) {
74394
74429
 
74395
74430
  // src/selfUpdate.ts
74396
74431
  import { spawnSync as spawnSync3 } from "child_process";
74397
- import { readFileSync as readFileSync10 } from "fs";
74432
+ import { readFileSync as readFileSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, renameSync as renameSync3 } from "fs";
74433
+ import { homedir as homedir8 } from "os";
74434
+ import { dirname as dirname8, basename as basename3, join as join10 } from "path";
74435
+ import { fileURLToPath as fileURLToPath2 } from "url";
74398
74436
  var PACKAGE_NAME = "openmates";
74399
- var DEFAULT_TARGET = "latest";
74437
+ function channelFile() {
74438
+ return join10(homedir8(), ".openmates", "updates.json");
74439
+ }
74440
+ function parseChannel(value) {
74441
+ if (value === "dev") return "dev";
74442
+ if (value === "stable" || value === "main") return "stable";
74443
+ throw new Error("--channel must be dev, stable, or main (alias for stable)");
74444
+ }
74445
+ function savedChannel() {
74446
+ try {
74447
+ return parseChannel(JSON.parse(readFileSync10(channelFile(), "utf8")).channel);
74448
+ } catch (error) {
74449
+ if (error.code === "ENOENT") {
74450
+ return getCliPackageVersion().includes("-") ? "dev" : "stable";
74451
+ }
74452
+ throw error;
74453
+ }
74454
+ }
74455
+ function persistSelfUpdateChannel(plan) {
74456
+ if (plan.dryRun || !plan.persistChannel) return;
74457
+ const path2 = channelFile();
74458
+ mkdirSync8(dirname8(path2), { recursive: true, mode: 448 });
74459
+ const temporary = `${path2}.${process.pid}.tmp`;
74460
+ writeFileSync8(temporary, JSON.stringify({ channel: plan.channel }) + "\n", { mode: 384 });
74461
+ renameSync3(temporary, path2);
74462
+ }
74463
+ function installedNpmPrefix(moduleUrl = import.meta.url, platform4 = process.platform) {
74464
+ const packageRoot = dirname8(dirname8(fileURLToPath2(moduleUrl)));
74465
+ const modules = dirname8(packageRoot);
74466
+ if (basename3(packageRoot) !== PACKAGE_NAME || basename3(modules) !== "node_modules") return null;
74467
+ if (platform4 === "win32") return dirname8(modules);
74468
+ return basename3(dirname8(modules)) === "lib" ? dirname8(dirname8(modules)) : null;
74469
+ }
74470
+ function compareVersions(left, right) {
74471
+ const parse = (value) => {
74472
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
74473
+ if (!match) throw new Error(`Cannot compare CLI version '${value}'`);
74474
+ return { core: match.slice(1, 4).map(BigInt), pre: match[4]?.split(".") };
74475
+ };
74476
+ const a = parse(left), b = parse(right);
74477
+ for (let i = 0; i < 3; i++) if (a.core[i] !== b.core[i]) return a.core[i] > b.core[i] ? 1 : -1;
74478
+ if (!a.pre || !b.pre) return a.pre ? -1 : b.pre ? 1 : 0;
74479
+ for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {
74480
+ const x = a.pre[i], y = b.pre[i];
74481
+ if (x === y) continue;
74482
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
74483
+ const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
74484
+ if (nx && ny) return BigInt(x) > BigInt(y) ? 1 : BigInt(x) < BigInt(y) ? -1 : 0;
74485
+ if (nx !== ny) return nx ? -1 : 1;
74486
+ return x > y ? 1 : -1;
74487
+ }
74488
+ return 0;
74489
+ }
74400
74490
  var SAFE_TARGET_RE = /^[a-zA-Z0-9._@+~:-]+$/;
74401
74491
  function getCliPackageVersion() {
74402
74492
  try {
@@ -74408,10 +74498,14 @@ function getCliPackageVersion() {
74408
74498
  }
74409
74499
  function buildSelfUpdatePlan(flags) {
74410
74500
  const packageManager = parsePackageManager(flags["package-manager"]);
74411
- const target = parseTarget(flags.version);
74501
+ const channel = flags.channel === void 0 ? savedChannel() : parseChannel(flags.channel);
74502
+ const target = parseTarget(flags.version ?? (channel === "dev" ? "alpha" : "latest"));
74412
74503
  const packageSpec = `${PACKAGE_NAME}@${target}`;
74413
74504
  const { command, args } = commandForPackageManager(packageManager, packageSpec);
74414
74505
  return {
74506
+ channel,
74507
+ persistChannel: flags.channel !== void 0,
74508
+ allowDowngrade: flags["allow-downgrade"] === true,
74415
74509
  packageManager,
74416
74510
  command,
74417
74511
  args,
@@ -74434,7 +74528,7 @@ function checkSelfUpdateStatus(plan) {
74434
74528
  return {
74435
74529
  currentVersion: plan.currentVersion,
74436
74530
  latestVersion: latest.version,
74437
- updateAvailable: plan.currentVersion !== latest.version,
74531
+ updateAvailable: compareVersions(latest.version, plan.currentVersion) > 0 || plan.allowDowngrade && compareVersions(latest.version, plan.currentVersion) !== 0,
74438
74532
  checkError: null
74439
74533
  };
74440
74534
  }
@@ -74464,7 +74558,8 @@ function resolveTargetVersion(target) {
74464
74558
  }
74465
74559
  const result = spawnSync3(commandName("npm"), ["view", `${PACKAGE_NAME}@${target}`, "version"], {
74466
74560
  encoding: "utf-8",
74467
- stdio: ["ignore", "pipe", "pipe"]
74561
+ stdio: ["ignore", "pipe", "pipe"],
74562
+ timeout: 3e4
74468
74563
  });
74469
74564
  if (result.error) return { version: null, error: result.error.message };
74470
74565
  if (result.status !== 0) {
@@ -74480,7 +74575,7 @@ function parsePackageManager(value) {
74480
74575
  throw new Error("--package-manager must be one of npm, pnpm, yarn, or bun");
74481
74576
  }
74482
74577
  function parseTarget(value) {
74483
- if (value === void 0) return DEFAULT_TARGET;
74578
+ if (value === void 0) return "latest";
74484
74579
  if (typeof value !== "string" || value.length === 0) {
74485
74580
  throw new Error("--version requires a version or npm dist-tag");
74486
74581
  }
@@ -74500,15 +74595,16 @@ function commandForPackageManager(packageManager, packageSpec) {
74500
74595
  if (packageManager === "pnpm") return { command: commandName("pnpm"), args: ["add", "-g", packageSpec] };
74501
74596
  if (packageManager === "yarn") return { command: commandName("yarn"), args: ["global", "add", packageSpec] };
74502
74597
  if (packageManager === "bun") return { command: commandName("bun"), args: ["install", "-g", packageSpec] };
74503
- return { command: commandName("npm"), args: ["install", "-g", packageSpec] };
74598
+ const prefix = installedNpmPrefix();
74599
+ return { command: commandName("npm"), args: ["install", "-g", packageSpec, ...prefix ? ["--prefix", prefix] : []] };
74504
74600
  }
74505
74601
  function commandName(name) {
74506
74602
  return process.platform === "win32" ? `${name}.cmd` : name;
74507
74603
  }
74508
74604
 
74509
74605
  // src/workRecovery.ts
74510
- import { mkdirSync as mkdirSync8, renameSync as renameSync2, writeFileSync as writeFileSync8 } from "fs";
74511
- import { dirname as dirname8 } from "path";
74606
+ import { mkdirSync as mkdirSync9, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "fs";
74607
+ import { dirname as dirname9 } from "path";
74512
74608
  import { stringify } from "yaml";
74513
74609
  async function projectPlanAssumption(plan, masterKey, assumption) {
74514
74610
  const key = await planKeyFromRecord(plan.encrypted, masterKey);
@@ -74687,18 +74783,18 @@ function collectMismatchPaths(left, right, path2, mismatches) {
74687
74783
  }
74688
74784
  function writeWorkRecoveryAtomically(path2, document) {
74689
74785
  validateWorkRecoveryDocument(document);
74690
- mkdirSync8(dirname8(path2), { recursive: true, mode: 448 });
74786
+ mkdirSync9(dirname9(path2), { recursive: true, mode: 448 });
74691
74787
  const temporaryPath = `${path2}.tmp`;
74692
- writeFileSync8(temporaryPath, stringify(document, { sortMapEntries: true, lineWidth: 0 }), { encoding: "utf8", mode: 384 });
74693
- renameSync2(temporaryPath, path2);
74788
+ writeFileSync9(temporaryPath, stringify(document, { sortMapEntries: true, lineWidth: 0 }), { encoding: "utf8", mode: 384 });
74789
+ renameSync4(temporaryPath, path2);
74694
74790
  }
74695
74791
 
74696
74792
  // src/revolutBusinessCertificate.ts
74697
- import { execFileSync as execFileSync4 } from "child_process";
74698
- import { createSign, randomUUID as randomUUID13 } from "crypto";
74699
- import { chmodSync as chmodSync6, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync11 } from "fs";
74700
- import { homedir as homedir8 } from "os";
74701
- import { join as join10, resolve as resolve10 } from "path";
74793
+ import { execFileSync as execFileSync5 } from "child_process";
74794
+ import { createSign, randomUUID as randomUUID14 } from "crypto";
74795
+ import { chmodSync as chmodSync7, existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as readFileSync11 } from "fs";
74796
+ import { homedir as homedir9 } from "os";
74797
+ import { join as join11, resolve as resolve10 } from "path";
74702
74798
  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";
74703
74799
  var REVOLUT_BUSINESS_DEFAULT_SANDBOX_REDIRECT_URI = "https://app.dev.openmates.org/oauth/revolut-business/callback";
74704
74800
  var REVOLUT_BUSINESS_DEFAULT_PRODUCTION_REDIRECT_URI = "https://openmates.org/oauth/revolut-business/callback";
@@ -74708,7 +74804,7 @@ var REVOLUT_BUSINESS_AUDIENCE = "https://revolut.com";
74708
74804
  var CERTIFICATE_DAYS = "1825";
74709
74805
  var RSA_BITS = "2048";
74710
74806
  function defaultRevolutBusinessCertificateDir(environment) {
74711
- return join10(homedir8(), ".openmates", "revolut-business", environment);
74807
+ return join11(homedir9(), ".openmates", "revolut-business", environment);
74712
74808
  }
74713
74809
  function defaultRevolutBusinessRedirectUri(environment) {
74714
74810
  return environment === "sandbox" ? REVOLUT_BUSINESS_DEFAULT_SANDBOX_REDIRECT_URI : REVOLUT_BUSINESS_DEFAULT_PRODUCTION_REDIRECT_URI;
@@ -74731,7 +74827,7 @@ async function exchangeRevolutBusinessAuthorizationCode(options) {
74731
74827
  if (!clientId) throw new Error("Missing Revolut Business client ID.");
74732
74828
  const code = extractRevolutBusinessAuthorizationCode(options.codeOrRedirectUrl);
74733
74829
  if (!code) throw new Error("Missing Revolut Business authorization code.");
74734
- const privateKeyPem = options.privateKeyPem ?? readFileSync11(options.privateKeyPath ?? join10(defaultRevolutBusinessCertificateDir(environment), "privatecert.pem"), "utf8");
74830
+ const privateKeyPem = options.privateKeyPem ?? readFileSync11(options.privateKeyPath ?? join11(defaultRevolutBusinessCertificateDir(environment), "privatecert.pem"), "utf8");
74735
74831
  const redirectUri = (options.redirectUri ?? defaultRevolutBusinessRedirectUri(environment)).trim();
74736
74832
  const clientAssertion = generateRevolutBusinessClientAssertion({ clientId, privateKeyPem, redirectUri });
74737
74833
  const response = await fetch(environment === "sandbox" ? "https://sandbox-b2b.revolut.com/api/1.0/auth/token" : "https://b2b.revolut.com/api/1.0/auth/token", {
@@ -74769,7 +74865,7 @@ function generateRevolutBusinessClientAssertion(options) {
74769
74865
  aud: REVOLUT_BUSINESS_AUDIENCE,
74770
74866
  exp: now + 3600,
74771
74867
  iat: now,
74772
- jti: randomUUID13()
74868
+ jti: randomUUID14()
74773
74869
  });
74774
74870
  const unsigned = `${header2}.${payload}`;
74775
74871
  const signer = createSign("RSA-SHA256");
@@ -74784,17 +74880,17 @@ function generateRevolutBusinessCertificate(options = {}) {
74784
74880
  const redirectUri = (options.redirectUri ?? defaultRevolutBusinessRedirectUri(environment)).trim();
74785
74881
  if (!title) throw new Error("Revolut certificate title must not be empty.");
74786
74882
  if (!redirectUri.startsWith("https://")) throw new Error("Revolut OAuth redirect URI must start with https://.");
74787
- mkdirSync9(outputDir, { recursive: true, mode: 448 });
74788
- chmodSync6(outputDir, 448);
74789
- const privateKeyPath = join10(outputDir, "privatecert.pem");
74790
- const publicCertificatePath = join10(outputDir, "publiccert.cer");
74883
+ mkdirSync10(outputDir, { recursive: true, mode: 448 });
74884
+ chmodSync7(outputDir, 448);
74885
+ const privateKeyPath = join11(outputDir, "privatecert.pem");
74886
+ const publicCertificatePath = join11(outputDir, "publiccert.cer");
74791
74887
  if (!options.overwrite && (existsSync12(privateKeyPath) || existsSync12(publicCertificatePath))) {
74792
74888
  throw new Error(`Revolut certificate files already exist in ${outputDir}. Re-run with --overwrite to replace them.`);
74793
74889
  }
74794
74890
  try {
74795
- execFileSync4("openssl", ["genrsa", "-out", privateKeyPath, RSA_BITS], { stdio: "ignore" });
74796
- chmodSync6(privateKeyPath, 384);
74797
- execFileSync4(
74891
+ execFileSync5("openssl", ["genrsa", "-out", privateKeyPath, RSA_BITS], { stdio: "ignore" });
74892
+ chmodSync7(privateKeyPath, 384);
74893
+ execFileSync5(
74798
74894
  "openssl",
74799
74895
  [
74800
74896
  "req",
@@ -75252,11 +75348,14 @@ function handleSupport(flags) {
75252
75348
  function handleSelfUpdate(command, flags) {
75253
75349
  const plan = buildSelfUpdatePlan(flags);
75254
75350
  const status = checkSelfUpdateStatus(plan);
75255
- const shouldInstall = status.updateAvailable !== false;
75351
+ if (status.checkError) throw new Error(`Update check failed: ${status.checkError}`);
75352
+ const shouldInstall = status.updateAvailable === true;
75256
75353
  if (flags.json === true) {
75257
75354
  if (!plan.dryRun && shouldInstall) runSelfUpdate(plan, { verbose: flags.verbose === true });
75355
+ persistSelfUpdateChannel(plan);
75258
75356
  printJson2({
75259
75357
  command,
75358
+ channel: plan.channel,
75260
75359
  status: status.updateAvailable === false ? "up_to_date" : plan.dryRun ? "planned" : "success",
75261
75360
  current_version: plan.currentVersion,
75262
75361
  latest_version: status.latestVersion,
@@ -75273,6 +75372,7 @@ function handleSelfUpdate(command, flags) {
75273
75372
  console.log("");
75274
75373
  console.log("Checking for updates...");
75275
75374
  console.log("");
75375
+ console.log(`Release channel: ${plan.channel}`);
75276
75376
  console.log(`Current version: ${plan.currentVersion}`);
75277
75377
  console.log(`Latest version: ${status.latestVersion ?? "unknown"}`);
75278
75378
  if (status.checkError) {
@@ -75288,11 +75388,13 @@ function handleSelfUpdate(command, flags) {
75288
75388
  return;
75289
75389
  }
75290
75390
  if (status.updateAvailable === false) {
75391
+ persistSelfUpdateChannel(plan);
75291
75392
  console.log("OpenMates CLI is already up to date.");
75292
75393
  return;
75293
75394
  }
75294
75395
  console.log(`Updating OpenMates CLI with ${plan.packageManager}...`);
75295
75396
  runSelfUpdate(plan, { verbose: flags.verbose === true });
75397
+ persistSelfUpdateChannel(plan);
75296
75398
  console.log(`Installed OpenMates CLI ${status.latestVersion ?? plan.target}.`);
75297
75399
  console.log("");
75298
75400
  console.log("OpenMates is up to date.");
@@ -75305,6 +75407,7 @@ function handleCliVersion(flags) {
75305
75407
  if (flags.json === true) {
75306
75408
  printJson2({
75307
75409
  command: "version",
75410
+ channel: plan.channel,
75308
75411
  current_version: status.currentVersion,
75309
75412
  latest_version: status.latestVersion,
75310
75413
  update_available: status.updateAvailable,
@@ -75314,6 +75417,7 @@ function handleCliVersion(flags) {
75314
75417
  return;
75315
75418
  }
75316
75419
  console.log(`OpenMates CLI ${status.currentVersion}`);
75420
+ console.log(`Release channel: ${plan.channel}`);
75317
75421
  if (status.checkError) {
75318
75422
  console.log(`Update check failed: ${status.checkError}`);
75319
75423
  return;
@@ -76081,7 +76185,7 @@ async function resolveAddToProjectStorageChoice(client, project, flags, objectTy
76081
76185
  async function createEncryptedProjectItem(client, project, input) {
76082
76186
  const timestamp = nowSeconds3();
76083
76187
  return client.createProjectItem(project.projectId, {
76084
- project_item_id: randomUUID14(),
76188
+ project_item_id: randomUUID15(),
76085
76189
  folder_id: input.folderId ?? null,
76086
76190
  item_type: input.itemType,
76087
76191
  target_id: input.targetId,
@@ -76275,7 +76379,7 @@ async function handlePlans(client, subcommand, rest, flags, redactor) {
76275
76379
  const encryptedSources = proof.length ? await encryptPlanAssumptionSources(plan, masterKey, proof) : void 0;
76276
76380
  if (action === "create" || action === "add") {
76277
76381
  const assumption = await client.createPlanAssumption(plan.planId, {
76278
- assumption_id: typeof flags.id === "string" ? flags.id : randomUUID14(),
76382
+ assumption_id: typeof flags.id === "string" ? flags.id : randomUUID15(),
76279
76383
  encrypted_text: await encryptPlanAssumptionSources(plan, masterKey, requiredStringFlag(flags.text ?? rest.slice(2).join(" "), "--text <assumption>")),
76280
76384
  status: typeof flags.status === "string" ? flags.status : void 0,
76281
76385
  linked_sub_chat_id: typeof flags["sub-chat"] === "string" ? flags["sub-chat"] : void 0,
@@ -77200,7 +77304,7 @@ async function handleProjects(client, subcommand, rest, flags, redactor) {
77200
77304
  const name = requiredStringFlag(rest[0] ?? flags.name, "project name");
77201
77305
  const projectKey = randomBytes9(32);
77202
77306
  const wrapping = await client.projectWrappingKey(context);
77203
- const projectId = randomUUID14();
77307
+ const projectId = randomUUID15();
77204
77308
  const timestamp = nowSeconds3();
77205
77309
  const slugMetadata = await buildEncryptedObjectSlugMetadata({
77206
77310
  value: typeof flags.slug === "string" ? flags.slug : name,
@@ -77308,7 +77412,7 @@ async function handleProjects(client, subcommand, rest, flags, redactor) {
77308
77412
  const proposal = isShortWorkspaceAsk(instruction) ? { name: instruction, description: "", icon: "folder", color: "default" } : extractRecord(await client.planProjectAsk({ instruction }), "proposed_project");
77309
77413
  const projectKey = randomBytes9(32);
77310
77414
  const timestamp = Math.floor(Date.now() / 1e3);
77311
- const projectId = randomUUID14();
77415
+ const projectId = randomUUID15();
77312
77416
  const name = requiredString(proposal, "name", instruction);
77313
77417
  const slugMetadata = await buildEncryptedObjectSlugMetadata({
77314
77418
  value: typeof flags.slug === "string" ? flags.slug : name,
@@ -77705,7 +77809,7 @@ async function handleTeams(client, subcommand, rest, flags) {
77705
77809
  if (action === "get") {
77706
77810
  const output = requiredStringFlag(flags.output ?? flags.file ?? rest[2], "--output <path>");
77707
77811
  const image = await client.getTeamProfileImage(teamId);
77708
- writeFileSync9(output, image.data, { mode: 384 });
77812
+ writeFileSync10(output, image.data, { mode: 384 });
77709
77813
  if (flags.json === true) printJson2({ output, content_type: image.contentType, size_bytes: image.data.byteLength });
77710
77814
  else console.log(`Team profile image written: ${output}`);
77711
77815
  return;
@@ -77864,7 +77968,7 @@ async function handleTeams(client, subcommand, rest, flags) {
77864
77968
  const output = requiredStringFlag(flags.output, "--output <path>");
77865
77969
  const result = await client.exportTeamData(teamId);
77866
77970
  const artifact = result.artifact && typeof result.artifact === "object" ? result.artifact : result;
77867
- writeFileSync9(output, `${JSON.stringify(artifact, null, 2)}
77971
+ writeFileSync10(output, `${JSON.stringify(artifact, null, 2)}
77868
77972
  `, { encoding: "utf-8", mode: 384 });
77869
77973
  if (flags.json === true) printJson2({ ...result, output });
77870
77974
  else console.log(`Team export written: ${output}`);
@@ -78207,7 +78311,7 @@ async function handleRemoteAccess(client, subcommand, rest, flags) {
78207
78311
  const projects = await loadProjects(client, masterKey, hostingFlags, hostingContext);
78208
78312
  const bindings = await resolveRemoteAccessBindings(client, masterKey, projects, candidateRoots, hostingFlags, hostingContext);
78209
78313
  if (bindings.length === 0) throw new Error("No Project folders were approved for remote access.");
78210
- const sourceSessionId = randomUUID14();
78314
+ const sourceSessionId = randomUUID15();
78211
78315
  const controller = new AbortController();
78212
78316
  const stop = () => controller.abort();
78213
78317
  process.once("SIGINT", stop);
@@ -78314,8 +78418,8 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
78314
78418
  const answer = (await promptLine2(`Create ${unresolved.length} missing Project${unresolved.length === 1 ? "" : "s"}? [y/N] `)).trim().toLowerCase();
78315
78419
  if (answer !== "y" && answer !== "yes") throw new Error("Remote access Project creation cancelled.");
78316
78420
  for (const rootPath of unresolved) {
78317
- const project = await createEncryptedRemoteAccessProject(client, masterKey, basename3(rootPath), context);
78318
- resolved.push({ rootPath, project, sourceId: randomUUID14() });
78421
+ const project = await createEncryptedRemoteAccessProject(client, masterKey, basename4(rootPath), context);
78422
+ resolved.push({ rootPath, project, sourceId: randomUUID15() });
78319
78423
  }
78320
78424
  }
78321
78425
  const bindings = [];
@@ -78326,7 +78430,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
78326
78430
  projectId: item.project.projectId,
78327
78431
  rootPath: item.rootPath,
78328
78432
  sourceType,
78329
- displayName: basename3(item.rootPath)
78433
+ displayName: basename4(item.rootPath)
78330
78434
  });
78331
78435
  const remoteSources = await client.listProjectSources(item.project.projectId, context);
78332
78436
  const remoteSource = remoteSources.find((entry) => entry.source_id === source.sourceId);
@@ -78352,7 +78456,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
78352
78456
  }
78353
78457
  async function createEncryptedRemoteAccessProject(client, masterKey, name, context) {
78354
78458
  const projectKey = randomBytes9(32);
78355
- const projectId = randomUUID14();
78459
+ const projectId = randomUUID15();
78356
78460
  const timestamp = Math.floor(Date.now() / 1e3);
78357
78461
  const wrapping = await client.projectWrappingKey(context);
78358
78462
  const payload = {
@@ -79169,16 +79273,16 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79169
79273
  }
79170
79274
  }
79171
79275
  const { mkdir: mkdir2, writeFile: writeFile2 } = await import("fs/promises");
79172
- const { join: join11 } = await import("path");
79276
+ const { join: join12 } = await import("path");
79173
79277
  if (useZip) {
79174
- const tmpDir = join11(outputDir, `.${filenameBase}_tmp`);
79278
+ const tmpDir = join12(outputDir, `.${filenameBase}_tmp`);
79175
79279
  await mkdir2(tmpDir, { recursive: true });
79176
- await writeFile2(join11(tmpDir, `${filenameBase}.yml`), yamlContent);
79177
- await writeFile2(join11(tmpDir, `${filenameBase}.md`), mdContent);
79280
+ await writeFile2(join12(tmpDir, `${filenameBase}.yml`), yamlContent);
79281
+ await writeFile2(join12(tmpDir, `${filenameBase}.md`), mdContent);
79178
79282
  if (codeEmbeds.length > 0) {
79179
79283
  for (const ce of codeEmbeds) {
79180
79284
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
79181
- const fullPath = join11(tmpDir, "code", fpath);
79285
+ const fullPath = join12(tmpDir, "code", fpath);
79182
79286
  await mkdir2(fullPath.substring(0, fullPath.lastIndexOf("/")), {
79183
79287
  recursive: true
79184
79288
  });
@@ -79186,13 +79290,13 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79186
79290
  }
79187
79291
  }
79188
79292
  if (transcriptEmbeds.length > 0) {
79189
- const tDir = join11(tmpDir, "transcripts");
79293
+ const tDir = join12(tmpDir, "transcripts");
79190
79294
  await mkdir2(tDir, { recursive: true });
79191
79295
  for (const te of transcriptEmbeds) {
79192
- await writeFile2(join11(tDir, te.filename), te.content);
79296
+ await writeFile2(join12(tDir, te.filename), te.content);
79193
79297
  }
79194
79298
  }
79195
- const zipPath = join11(outputDir, `${filenameBase}.zip`);
79299
+ const zipPath = join12(outputDir, `${filenameBase}.zip`);
79196
79300
  const { execSync: execSync2 } = await import("child_process");
79197
79301
  try {
79198
79302
  execSync2(`cd "${tmpDir}" && zip -r "${zipPath}" .`, { stdio: "pipe" });
@@ -79207,17 +79311,17 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79207
79311
  );
79208
79312
  }
79209
79313
  } else {
79210
- const chatDir = join11(outputDir, filenameBase);
79314
+ const chatDir = join12(outputDir, filenameBase);
79211
79315
  await mkdir2(chatDir, { recursive: true });
79212
79316
  const written = [];
79213
- await writeFile2(join11(chatDir, `${filenameBase}.yml`), yamlContent);
79317
+ await writeFile2(join12(chatDir, `${filenameBase}.yml`), yamlContent);
79214
79318
  written.push(`${filenameBase}.yml`);
79215
- await writeFile2(join11(chatDir, `${filenameBase}.md`), mdContent);
79319
+ await writeFile2(join12(chatDir, `${filenameBase}.md`), mdContent);
79216
79320
  written.push(`${filenameBase}.md`);
79217
79321
  if (codeEmbeds.length > 0) {
79218
79322
  for (const ce of codeEmbeds) {
79219
79323
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
79220
- const fullPath = join11(chatDir, "code", fpath);
79324
+ const fullPath = join12(chatDir, "code", fpath);
79221
79325
  await mkdir2(fullPath.substring(0, fullPath.lastIndexOf("/")), {
79222
79326
  recursive: true
79223
79327
  });
@@ -79226,10 +79330,10 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79226
79330
  }
79227
79331
  }
79228
79332
  if (transcriptEmbeds.length > 0) {
79229
- const tDir = join11(chatDir, "transcripts");
79333
+ const tDir = join12(chatDir, "transcripts");
79230
79334
  await mkdir2(tDir, { recursive: true });
79231
79335
  for (const te of transcriptEmbeds) {
79232
- await writeFile2(join11(tDir, te.filename), te.content);
79336
+ await writeFile2(join12(tDir, te.filename), te.content);
79233
79337
  written.push(`transcripts/${te.filename}`);
79234
79338
  }
79235
79339
  }
@@ -79265,7 +79369,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79265
79369
  printJson2({
79266
79370
  chat_id: chat.id,
79267
79371
  title: chat.title,
79268
- output_dir: useZip ? join11(outputDir, `${filenameBase}.zip`) : join11(outputDir, filenameBase),
79372
+ output_dir: useZip ? join12(outputDir, `${filenameBase}.zip`) : join12(outputDir, filenameBase),
79269
79373
  files,
79270
79374
  code_embeds: codeEmbeds.length,
79271
79375
  transcript_embeds: transcriptEmbeds.length
@@ -80291,7 +80395,7 @@ function buildImagesAiDetectionSummary(uploadResult, filePath) {
80291
80395
  const classification = classifyImagesAiDetection(score);
80292
80396
  return {
80293
80397
  file: filePath,
80294
- filename: uploadResult.filename || basename3(filePath),
80398
+ filename: uploadResult.filename || basename4(filePath),
80295
80399
  content_type: uploadResult.content_type,
80296
80400
  embed_id: uploadResult.embed_id,
80297
80401
  deduplicated: uploadResult.deduplicated,
@@ -81322,7 +81426,7 @@ async function handleEmbeds(client, subcommand, rest, flags) {
81322
81426
  throw new Error("Embed version content was not available after local reconstruction.");
81323
81427
  }
81324
81428
  if (typeof flags.output === "string") {
81325
- writeFileSync9(flags.output, result.content, "utf-8");
81429
+ writeFileSync10(flags.output, result.content, "utf-8");
81326
81430
  if (flags.json === true) {
81327
81431
  printJson2({ ...result, output: flags.output });
81328
81432
  } else {
@@ -81606,12 +81710,12 @@ async function parseAccountImportFile(parserFormat, file, flags = {}) {
81606
81710
  const selectedSource = requestedSource;
81607
81711
  if (parserFormat === "generic") {
81608
81712
  if (selectedSource !== "gemini" && selectedSource !== "other") throw new Error("Generic account import requires --source gemini or --source other.");
81609
- return parseGenericImportBuffer(payload, basename3(file), selectedSource);
81713
+ return parseGenericImportBuffer(payload, basename4(file), selectedSource);
81610
81714
  }
81611
- if (parserFormat === "claude") return parseClaudeImportBuffer(payload, basename3(file), selectedSource);
81612
- if (parserFormat === "chatgpt") return parseChatGPTImportBuffer(payload, basename3(file), selectedSource);
81613
- if (parserFormat === "opencode") return parseOpenCodeImportBuffer(payload, basename3(file), selectedSource);
81614
- return parseOpenMatesImportBuffer(payload, basename3(file), typeof flags.password === "string" ? flags.password : void 0, selectedSource);
81715
+ if (parserFormat === "claude") return parseClaudeImportBuffer(payload, basename4(file), selectedSource);
81716
+ if (parserFormat === "chatgpt") return parseChatGPTImportBuffer(payload, basename4(file), selectedSource);
81717
+ if (parserFormat === "opencode") return parseOpenCodeImportBuffer(payload, basename4(file), selectedSource);
81718
+ return parseOpenMatesImportBuffer(payload, basename4(file), typeof flags.password === "string" ? flags.password : void 0, selectedSource);
81615
81719
  }
81616
81720
  async function runAccountImport(client, parserFormat, file, flags) {
81617
81721
  if (parserFormat === "generic" && typeof flags.source !== "string") throw new Error("Generic account import requires --source gemini or --source other.");
@@ -81650,7 +81754,7 @@ async function runAccountImport(client, parserFormat, file, flags) {
81650
81754
  if (flags.yes !== true) {
81651
81755
  await confirmOrExit(`Import ${selectedCount} chat(s) into new encrypted OpenMates chats? [y/N] `);
81652
81756
  }
81653
- const importId = typeof preview.import_id === "string" ? preview.import_id : randomUUID14();
81757
+ const importId = typeof preview.import_id === "string" ? preview.import_id : randomUUID15();
81654
81758
  const selectedChats = parsed.chats.slice(0, selectedCount);
81655
81759
  const selectedFingerprints = selectedChats.map((chat) => chat.source_fingerprint);
81656
81760
  const confirmation = await client.confirmAccountImport(importId, selectedFingerprints);
@@ -81981,11 +82085,11 @@ function parseYamlScalar(value) {
81981
82085
  }
81982
82086
  async function saveDownloadedDocument(document, output) {
81983
82087
  const { mkdir: mkdir2, writeFile: writeFile2 } = await import("fs/promises");
81984
- const { join: join11, basename: basename4, dirname: dirname10 } = await import("path");
82088
+ const { join: join12, basename: basename5, dirname: dirname11 } = await import("path");
81985
82089
  const target = typeof output === "string" ? output : ".";
81986
- const filename = basename4(document.filename || "document.pdf");
81987
- const filePath = target.endsWith(".pdf") ? target : join11(target, filename);
81988
- await mkdir2(dirname10(filePath), { recursive: true });
82090
+ const filename = basename5(document.filename || "document.pdf");
82091
+ const filePath = target.endsWith(".pdf") ? target : join12(target, filename);
82092
+ await mkdir2(dirname11(filePath), { recursive: true });
81989
82093
  await writeFile2(filePath, document.data);
81990
82094
  return filePath;
81991
82095
  }
@@ -82144,8 +82248,8 @@ async function handleFinance(client, subcommand, _rest, flags) {
82144
82248
  refresh_token_envelope: connectedAccount.refreshTokenBundle
82145
82249
  }
82146
82250
  ] : [],
82147
- chatId: `cli-finance-${randomUUID14()}`,
82148
- messageId: `cli-finance-message-${randomUUID14()}`,
82251
+ chatId: `cli-finance-${randomUUID15()}`,
82252
+ messageId: `cli-finance-message-${randomUUID15()}`,
82149
82253
  apiKey: resolveApiKey(flags) ?? void 0,
82150
82254
  promptInjectionProtection: false
82151
82255
  });
@@ -82157,7 +82261,7 @@ async function handleFinance(client, subcommand, _rest, flags) {
82157
82261
  }
82158
82262
  function readFinanceCsvStatements(flags) {
82159
82263
  const paths = parseCsvFlag(flags.csv) ?? [];
82160
- return paths.map((filePath) => ({ filename: basename3(filePath), content: readFileSync12(filePath, "utf8") }));
82264
+ return paths.map((filePath) => ({ filename: basename4(filePath), content: readFileSync12(filePath, "utf8") }));
82161
82265
  }
82162
82266
  function buildFinanceCheckAccountsInput(flags, csvStatements, connectedAccount) {
82163
82267
  const input = {
@@ -82452,7 +82556,7 @@ async function promptPlainText(question) {
82452
82556
  }
82453
82557
  async function writeSecretFile(filePath, content, force = false) {
82454
82558
  const { mkdir: mkdir2, writeFile: writeFile2, stat: stat2 } = await import("fs/promises");
82455
- const { dirname: dirname10 } = await import("path");
82559
+ const { dirname: dirname11 } = await import("path");
82456
82560
  try {
82457
82561
  await stat2(filePath);
82458
82562
  if (!force) throw new Error(`${filePath} already exists. Use --force to overwrite.`);
@@ -82462,7 +82566,7 @@ async function writeSecretFile(filePath, content, force = false) {
82462
82566
  }
82463
82567
  if (error instanceof Error && !("code" in error)) throw error;
82464
82568
  }
82465
- await mkdir2(dirname10(filePath), { recursive: true });
82569
+ await mkdir2(dirname11(filePath), { recursive: true });
82466
82570
  await writeFile2(filePath, content, { mode: 384 });
82467
82571
  return filePath;
82468
82572
  }
@@ -85628,12 +85732,16 @@ function printSelfUpdateHelp() {
85628
85732
  openmates update [--version <version|tag>] [--package-manager <name>] [--dry-run] [--verbose] [--json]
85629
85733
  openmates upgrade [--version <version|tag>] [--package-manager <name>] [--dry-run] [--verbose] [--json]
85630
85734
 
85631
- Updates the globally installed openmates package. The default target is latest.
85735
+ Updates the globally installed openmates package using the saved release channel.
85736
+ Stable installations default to stable; prereleases default to dev.
85737
+ Channel changes persist only after a successful update or up-to-date check.
85632
85738
 
85633
85739
  Options:
85634
- --version <version|tag> Install a specific npm version or dist-tag (default: latest)
85740
+ --version <version|tag> Install a specific npm version or dist-tag (one-time override)
85635
85741
  --package-manager <name> npm, pnpm, yarn, or bun (default: detect, then npm)
85636
85742
  --dry-run Print the package-manager command without running it
85743
+ --channel <dev|stable|main> Save release channel (dev uses npm alpha; stable/main uses latest)
85744
+ --allow-downgrade Explicitly allow installing an older version
85637
85745
  --verbose Stream package-manager output during installation
85638
85746
  --json Output the update plan/result as JSON`);
85639
85747
  }
@@ -86440,7 +86548,7 @@ async function handleDocs(client, subcommand, rest, flags) {
86440
86548
  }
86441
86549
  if (subcommand === "download") {
86442
86550
  const { writeFile: writeFile2, mkdir: mkdir2 } = await import("fs/promises");
86443
- const { join: join11, dirname: dirname10 } = await import("path");
86551
+ const { join: join12, dirname: dirname11 } = await import("path");
86444
86552
  if (flags.all === true) {
86445
86553
  const outputDir = typeof flags.output === "string" ? flags.output : "./openmates-docs";
86446
86554
  const tree = await client.listDocs();
@@ -86449,8 +86557,8 @@ async function handleDocs(client, subcommand, rest, flags) {
86449
86557
  let count = 0;
86450
86558
  for (const slug2 of slugs) {
86451
86559
  const content2 = await client.getDoc(slug2);
86452
- const filePath = join11(outputDir, `${slug2}.md`);
86453
- await mkdir2(dirname10(filePath), { recursive: true });
86560
+ const filePath = join12(outputDir, `${slug2}.md`);
86561
+ await mkdir2(dirname11(filePath), { recursive: true });
86454
86562
  await writeFile2(filePath, content2, "utf-8");
86455
86563
  count++;
86456
86564
  process.stderr.write(`\r Downloaded ${count}/${slugs.length}`);
@@ -86522,8 +86630,8 @@ function isCliEntrypoint() {
86522
86630
  if (!entrypoint) return false;
86523
86631
  try {
86524
86632
  const invokedPath = realpathSync2(entrypoint);
86525
- const modulePath = realpathSync2(fileURLToPath2(import.meta.url));
86526
- return invokedPath === modulePath || basename3(invokedPath) === "cli.js" && dirname9(invokedPath) === dirname9(modulePath);
86633
+ const modulePath = realpathSync2(fileURLToPath3(import.meta.url));
86634
+ return invokedPath === modulePath || basename4(invokedPath) === "cli.js" && dirname10(invokedPath) === dirname10(modulePath);
86527
86635
  } catch {
86528
86636
  return false;
86529
86637
  }
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  resolveProjectContext,
12
12
  serializeToYaml,
13
13
  shouldRequireTrustedAccountGuard
14
- } from "./chunk-RLOO6QKC.js";
14
+ } from "./chunk-65ZA6VF2.js";
15
15
  import "./chunk-IWKP55ZB.js";
16
16
  import "./chunk-BBKJZ23O.js";
17
17
  export {
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ import {
42
42
  selectAssistantMessagesForSpeech,
43
43
  serializeToYaml,
44
44
  summarizeAssistantSpeech
45
- } from "./chunk-RLOO6QKC.js";
45
+ } from "./chunk-65ZA6VF2.js";
46
46
  import "./chunk-IWKP55ZB.js";
47
47
  import "./chunk-BBKJZ23O.js";
48
48
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmates",
3
- "version": "0.18.0-alpha.1",
3
+ "version": "0.18.0-alpha.3",
4
4
  "description": "OpenMates CLI and SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",