openmates 0.18.0-alpha.2 → 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,9 +24298,9 @@ 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";
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
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";
@@ -48948,9 +48948,9 @@ function basenameFromUrl(url) {
48948
48948
  return withoutQuery.split("/").pop()?.replace(/[^a-zA-Z0-9._-]/g, "_") ?? "";
48949
48949
  }
48950
48950
  function extensionFromUrl(url) {
48951
- const basename4 = basenameFromUrl(url);
48952
- const dotIndex = basename4.lastIndexOf(".");
48953
- 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() : "";
48954
48954
  }
48955
48955
  function extensionFromLanguage(language) {
48956
48956
  const normalized = language.toLowerCase();
@@ -74429,9 +74429,64 @@ function remoteErrorMessage(code) {
74429
74429
 
74430
74430
  // src/selfUpdate.ts
74431
74431
  import { spawnSync as spawnSync3 } from "child_process";
74432
- 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";
74433
74436
  var PACKAGE_NAME = "openmates";
74434
- 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
+ }
74435
74490
  var SAFE_TARGET_RE = /^[a-zA-Z0-9._@+~:-]+$/;
74436
74491
  function getCliPackageVersion() {
74437
74492
  try {
@@ -74443,10 +74498,14 @@ function getCliPackageVersion() {
74443
74498
  }
74444
74499
  function buildSelfUpdatePlan(flags) {
74445
74500
  const packageManager = parsePackageManager(flags["package-manager"]);
74446
- 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"));
74447
74503
  const packageSpec = `${PACKAGE_NAME}@${target}`;
74448
74504
  const { command, args } = commandForPackageManager(packageManager, packageSpec);
74449
74505
  return {
74506
+ channel,
74507
+ persistChannel: flags.channel !== void 0,
74508
+ allowDowngrade: flags["allow-downgrade"] === true,
74450
74509
  packageManager,
74451
74510
  command,
74452
74511
  args,
@@ -74469,7 +74528,7 @@ function checkSelfUpdateStatus(plan) {
74469
74528
  return {
74470
74529
  currentVersion: plan.currentVersion,
74471
74530
  latestVersion: latest.version,
74472
- updateAvailable: plan.currentVersion !== latest.version,
74531
+ updateAvailable: compareVersions(latest.version, plan.currentVersion) > 0 || plan.allowDowngrade && compareVersions(latest.version, plan.currentVersion) !== 0,
74473
74532
  checkError: null
74474
74533
  };
74475
74534
  }
@@ -74499,7 +74558,8 @@ function resolveTargetVersion(target) {
74499
74558
  }
74500
74559
  const result = spawnSync3(commandName("npm"), ["view", `${PACKAGE_NAME}@${target}`, "version"], {
74501
74560
  encoding: "utf-8",
74502
- stdio: ["ignore", "pipe", "pipe"]
74561
+ stdio: ["ignore", "pipe", "pipe"],
74562
+ timeout: 3e4
74503
74563
  });
74504
74564
  if (result.error) return { version: null, error: result.error.message };
74505
74565
  if (result.status !== 0) {
@@ -74515,7 +74575,7 @@ function parsePackageManager(value) {
74515
74575
  throw new Error("--package-manager must be one of npm, pnpm, yarn, or bun");
74516
74576
  }
74517
74577
  function parseTarget(value) {
74518
- if (value === void 0) return DEFAULT_TARGET;
74578
+ if (value === void 0) return "latest";
74519
74579
  if (typeof value !== "string" || value.length === 0) {
74520
74580
  throw new Error("--version requires a version or npm dist-tag");
74521
74581
  }
@@ -74535,15 +74595,16 @@ function commandForPackageManager(packageManager, packageSpec) {
74535
74595
  if (packageManager === "pnpm") return { command: commandName("pnpm"), args: ["add", "-g", packageSpec] };
74536
74596
  if (packageManager === "yarn") return { command: commandName("yarn"), args: ["global", "add", packageSpec] };
74537
74597
  if (packageManager === "bun") return { command: commandName("bun"), args: ["install", "-g", packageSpec] };
74538
- return { command: commandName("npm"), args: ["install", "-g", packageSpec] };
74598
+ const prefix = installedNpmPrefix();
74599
+ return { command: commandName("npm"), args: ["install", "-g", packageSpec, ...prefix ? ["--prefix", prefix] : []] };
74539
74600
  }
74540
74601
  function commandName(name) {
74541
74602
  return process.platform === "win32" ? `${name}.cmd` : name;
74542
74603
  }
74543
74604
 
74544
74605
  // src/workRecovery.ts
74545
- import { mkdirSync as mkdirSync8, renameSync as renameSync3, writeFileSync as writeFileSync8 } from "fs";
74546
- 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";
74547
74608
  import { stringify } from "yaml";
74548
74609
  async function projectPlanAssumption(plan, masterKey, assumption) {
74549
74610
  const key = await planKeyFromRecord(plan.encrypted, masterKey);
@@ -74722,18 +74783,18 @@ function collectMismatchPaths(left, right, path2, mismatches) {
74722
74783
  }
74723
74784
  function writeWorkRecoveryAtomically(path2, document) {
74724
74785
  validateWorkRecoveryDocument(document);
74725
- mkdirSync8(dirname8(path2), { recursive: true, mode: 448 });
74786
+ mkdirSync9(dirname9(path2), { recursive: true, mode: 448 });
74726
74787
  const temporaryPath = `${path2}.tmp`;
74727
- writeFileSync8(temporaryPath, stringify(document, { sortMapEntries: true, lineWidth: 0 }), { encoding: "utf8", mode: 384 });
74728
- renameSync3(temporaryPath, path2);
74788
+ writeFileSync9(temporaryPath, stringify(document, { sortMapEntries: true, lineWidth: 0 }), { encoding: "utf8", mode: 384 });
74789
+ renameSync4(temporaryPath, path2);
74729
74790
  }
74730
74791
 
74731
74792
  // src/revolutBusinessCertificate.ts
74732
74793
  import { execFileSync as execFileSync5 } from "child_process";
74733
74794
  import { createSign, randomUUID as randomUUID14 } from "crypto";
74734
- import { chmodSync as chmodSync7, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync11 } from "fs";
74735
- import { homedir as homedir8 } from "os";
74736
- import { join as join10, resolve as resolve10 } from "path";
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";
74737
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";
74738
74799
  var REVOLUT_BUSINESS_DEFAULT_SANDBOX_REDIRECT_URI = "https://app.dev.openmates.org/oauth/revolut-business/callback";
74739
74800
  var REVOLUT_BUSINESS_DEFAULT_PRODUCTION_REDIRECT_URI = "https://openmates.org/oauth/revolut-business/callback";
@@ -74743,7 +74804,7 @@ var REVOLUT_BUSINESS_AUDIENCE = "https://revolut.com";
74743
74804
  var CERTIFICATE_DAYS = "1825";
74744
74805
  var RSA_BITS = "2048";
74745
74806
  function defaultRevolutBusinessCertificateDir(environment) {
74746
- return join10(homedir8(), ".openmates", "revolut-business", environment);
74807
+ return join11(homedir9(), ".openmates", "revolut-business", environment);
74747
74808
  }
74748
74809
  function defaultRevolutBusinessRedirectUri(environment) {
74749
74810
  return environment === "sandbox" ? REVOLUT_BUSINESS_DEFAULT_SANDBOX_REDIRECT_URI : REVOLUT_BUSINESS_DEFAULT_PRODUCTION_REDIRECT_URI;
@@ -74766,7 +74827,7 @@ async function exchangeRevolutBusinessAuthorizationCode(options) {
74766
74827
  if (!clientId) throw new Error("Missing Revolut Business client ID.");
74767
74828
  const code = extractRevolutBusinessAuthorizationCode(options.codeOrRedirectUrl);
74768
74829
  if (!code) throw new Error("Missing Revolut Business authorization code.");
74769
- 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");
74770
74831
  const redirectUri = (options.redirectUri ?? defaultRevolutBusinessRedirectUri(environment)).trim();
74771
74832
  const clientAssertion = generateRevolutBusinessClientAssertion({ clientId, privateKeyPem, redirectUri });
74772
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", {
@@ -74819,10 +74880,10 @@ function generateRevolutBusinessCertificate(options = {}) {
74819
74880
  const redirectUri = (options.redirectUri ?? defaultRevolutBusinessRedirectUri(environment)).trim();
74820
74881
  if (!title) throw new Error("Revolut certificate title must not be empty.");
74821
74882
  if (!redirectUri.startsWith("https://")) throw new Error("Revolut OAuth redirect URI must start with https://.");
74822
- mkdirSync9(outputDir, { recursive: true, mode: 448 });
74883
+ mkdirSync10(outputDir, { recursive: true, mode: 448 });
74823
74884
  chmodSync7(outputDir, 448);
74824
- const privateKeyPath = join10(outputDir, "privatecert.pem");
74825
- const publicCertificatePath = join10(outputDir, "publiccert.cer");
74885
+ const privateKeyPath = join11(outputDir, "privatecert.pem");
74886
+ const publicCertificatePath = join11(outputDir, "publiccert.cer");
74826
74887
  if (!options.overwrite && (existsSync12(privateKeyPath) || existsSync12(publicCertificatePath))) {
74827
74888
  throw new Error(`Revolut certificate files already exist in ${outputDir}. Re-run with --overwrite to replace them.`);
74828
74889
  }
@@ -75287,11 +75348,14 @@ function handleSupport(flags) {
75287
75348
  function handleSelfUpdate(command, flags) {
75288
75349
  const plan = buildSelfUpdatePlan(flags);
75289
75350
  const status = checkSelfUpdateStatus(plan);
75290
- const shouldInstall = status.updateAvailable !== false;
75351
+ if (status.checkError) throw new Error(`Update check failed: ${status.checkError}`);
75352
+ const shouldInstall = status.updateAvailable === true;
75291
75353
  if (flags.json === true) {
75292
75354
  if (!plan.dryRun && shouldInstall) runSelfUpdate(plan, { verbose: flags.verbose === true });
75355
+ persistSelfUpdateChannel(plan);
75293
75356
  printJson2({
75294
75357
  command,
75358
+ channel: plan.channel,
75295
75359
  status: status.updateAvailable === false ? "up_to_date" : plan.dryRun ? "planned" : "success",
75296
75360
  current_version: plan.currentVersion,
75297
75361
  latest_version: status.latestVersion,
@@ -75308,6 +75372,7 @@ function handleSelfUpdate(command, flags) {
75308
75372
  console.log("");
75309
75373
  console.log("Checking for updates...");
75310
75374
  console.log("");
75375
+ console.log(`Release channel: ${plan.channel}`);
75311
75376
  console.log(`Current version: ${plan.currentVersion}`);
75312
75377
  console.log(`Latest version: ${status.latestVersion ?? "unknown"}`);
75313
75378
  if (status.checkError) {
@@ -75323,11 +75388,13 @@ function handleSelfUpdate(command, flags) {
75323
75388
  return;
75324
75389
  }
75325
75390
  if (status.updateAvailable === false) {
75391
+ persistSelfUpdateChannel(plan);
75326
75392
  console.log("OpenMates CLI is already up to date.");
75327
75393
  return;
75328
75394
  }
75329
75395
  console.log(`Updating OpenMates CLI with ${plan.packageManager}...`);
75330
75396
  runSelfUpdate(plan, { verbose: flags.verbose === true });
75397
+ persistSelfUpdateChannel(plan);
75331
75398
  console.log(`Installed OpenMates CLI ${status.latestVersion ?? plan.target}.`);
75332
75399
  console.log("");
75333
75400
  console.log("OpenMates is up to date.");
@@ -75340,6 +75407,7 @@ function handleCliVersion(flags) {
75340
75407
  if (flags.json === true) {
75341
75408
  printJson2({
75342
75409
  command: "version",
75410
+ channel: plan.channel,
75343
75411
  current_version: status.currentVersion,
75344
75412
  latest_version: status.latestVersion,
75345
75413
  update_available: status.updateAvailable,
@@ -75349,6 +75417,7 @@ function handleCliVersion(flags) {
75349
75417
  return;
75350
75418
  }
75351
75419
  console.log(`OpenMates CLI ${status.currentVersion}`);
75420
+ console.log(`Release channel: ${plan.channel}`);
75352
75421
  if (status.checkError) {
75353
75422
  console.log(`Update check failed: ${status.checkError}`);
75354
75423
  return;
@@ -77740,7 +77809,7 @@ async function handleTeams(client, subcommand, rest, flags) {
77740
77809
  if (action === "get") {
77741
77810
  const output = requiredStringFlag(flags.output ?? flags.file ?? rest[2], "--output <path>");
77742
77811
  const image = await client.getTeamProfileImage(teamId);
77743
- writeFileSync9(output, image.data, { mode: 384 });
77812
+ writeFileSync10(output, image.data, { mode: 384 });
77744
77813
  if (flags.json === true) printJson2({ output, content_type: image.contentType, size_bytes: image.data.byteLength });
77745
77814
  else console.log(`Team profile image written: ${output}`);
77746
77815
  return;
@@ -77899,7 +77968,7 @@ async function handleTeams(client, subcommand, rest, flags) {
77899
77968
  const output = requiredStringFlag(flags.output, "--output <path>");
77900
77969
  const result = await client.exportTeamData(teamId);
77901
77970
  const artifact = result.artifact && typeof result.artifact === "object" ? result.artifact : result;
77902
- writeFileSync9(output, `${JSON.stringify(artifact, null, 2)}
77971
+ writeFileSync10(output, `${JSON.stringify(artifact, null, 2)}
77903
77972
  `, { encoding: "utf-8", mode: 384 });
77904
77973
  if (flags.json === true) printJson2({ ...result, output });
77905
77974
  else console.log(`Team export written: ${output}`);
@@ -78349,7 +78418,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
78349
78418
  const answer = (await promptLine2(`Create ${unresolved.length} missing Project${unresolved.length === 1 ? "" : "s"}? [y/N] `)).trim().toLowerCase();
78350
78419
  if (answer !== "y" && answer !== "yes") throw new Error("Remote access Project creation cancelled.");
78351
78420
  for (const rootPath of unresolved) {
78352
- const project = await createEncryptedRemoteAccessProject(client, masterKey, basename3(rootPath), context);
78421
+ const project = await createEncryptedRemoteAccessProject(client, masterKey, basename4(rootPath), context);
78353
78422
  resolved.push({ rootPath, project, sourceId: randomUUID15() });
78354
78423
  }
78355
78424
  }
@@ -78361,7 +78430,7 @@ async function resolveRemoteAccessBindings(client, masterKey, projects, candidat
78361
78430
  projectId: item.project.projectId,
78362
78431
  rootPath: item.rootPath,
78363
78432
  sourceType,
78364
- displayName: basename3(item.rootPath)
78433
+ displayName: basename4(item.rootPath)
78365
78434
  });
78366
78435
  const remoteSources = await client.listProjectSources(item.project.projectId, context);
78367
78436
  const remoteSource = remoteSources.find((entry) => entry.source_id === source.sourceId);
@@ -79204,16 +79273,16 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79204
79273
  }
79205
79274
  }
79206
79275
  const { mkdir: mkdir2, writeFile: writeFile2 } = await import("fs/promises");
79207
- const { join: join11 } = await import("path");
79276
+ const { join: join12 } = await import("path");
79208
79277
  if (useZip) {
79209
- const tmpDir = join11(outputDir, `.${filenameBase}_tmp`);
79278
+ const tmpDir = join12(outputDir, `.${filenameBase}_tmp`);
79210
79279
  await mkdir2(tmpDir, { recursive: true });
79211
- await writeFile2(join11(tmpDir, `${filenameBase}.yml`), yamlContent);
79212
- await writeFile2(join11(tmpDir, `${filenameBase}.md`), mdContent);
79280
+ await writeFile2(join12(tmpDir, `${filenameBase}.yml`), yamlContent);
79281
+ await writeFile2(join12(tmpDir, `${filenameBase}.md`), mdContent);
79213
79282
  if (codeEmbeds.length > 0) {
79214
79283
  for (const ce of codeEmbeds) {
79215
79284
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
79216
- const fullPath = join11(tmpDir, "code", fpath);
79285
+ const fullPath = join12(tmpDir, "code", fpath);
79217
79286
  await mkdir2(fullPath.substring(0, fullPath.lastIndexOf("/")), {
79218
79287
  recursive: true
79219
79288
  });
@@ -79221,13 +79290,13 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79221
79290
  }
79222
79291
  }
79223
79292
  if (transcriptEmbeds.length > 0) {
79224
- const tDir = join11(tmpDir, "transcripts");
79293
+ const tDir = join12(tmpDir, "transcripts");
79225
79294
  await mkdir2(tDir, { recursive: true });
79226
79295
  for (const te of transcriptEmbeds) {
79227
- await writeFile2(join11(tDir, te.filename), te.content);
79296
+ await writeFile2(join12(tDir, te.filename), te.content);
79228
79297
  }
79229
79298
  }
79230
- const zipPath = join11(outputDir, `${filenameBase}.zip`);
79299
+ const zipPath = join12(outputDir, `${filenameBase}.zip`);
79231
79300
  const { execSync: execSync2 } = await import("child_process");
79232
79301
  try {
79233
79302
  execSync2(`cd "${tmpDir}" && zip -r "${zipPath}" .`, { stdio: "pipe" });
@@ -79242,17 +79311,17 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79242
79311
  );
79243
79312
  }
79244
79313
  } else {
79245
- const chatDir = join11(outputDir, filenameBase);
79314
+ const chatDir = join12(outputDir, filenameBase);
79246
79315
  await mkdir2(chatDir, { recursive: true });
79247
79316
  const written = [];
79248
- await writeFile2(join11(chatDir, `${filenameBase}.yml`), yamlContent);
79317
+ await writeFile2(join12(chatDir, `${filenameBase}.yml`), yamlContent);
79249
79318
  written.push(`${filenameBase}.yml`);
79250
- await writeFile2(join11(chatDir, `${filenameBase}.md`), mdContent);
79319
+ await writeFile2(join12(chatDir, `${filenameBase}.md`), mdContent);
79251
79320
  written.push(`${filenameBase}.md`);
79252
79321
  if (codeEmbeds.length > 0) {
79253
79322
  for (const ce of codeEmbeds) {
79254
79323
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
79255
- const fullPath = join11(chatDir, "code", fpath);
79324
+ const fullPath = join12(chatDir, "code", fpath);
79256
79325
  await mkdir2(fullPath.substring(0, fullPath.lastIndexOf("/")), {
79257
79326
  recursive: true
79258
79327
  });
@@ -79261,10 +79330,10 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79261
79330
  }
79262
79331
  }
79263
79332
  if (transcriptEmbeds.length > 0) {
79264
- const tDir = join11(chatDir, "transcripts");
79333
+ const tDir = join12(chatDir, "transcripts");
79265
79334
  await mkdir2(tDir, { recursive: true });
79266
79335
  for (const te of transcriptEmbeds) {
79267
- await writeFile2(join11(tDir, te.filename), te.content);
79336
+ await writeFile2(join12(tDir, te.filename), te.content);
79268
79337
  written.push(`transcripts/${te.filename}`);
79269
79338
  }
79270
79339
  }
@@ -79300,7 +79369,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
79300
79369
  printJson2({
79301
79370
  chat_id: chat.id,
79302
79371
  title: chat.title,
79303
- output_dir: useZip ? join11(outputDir, `${filenameBase}.zip`) : join11(outputDir, filenameBase),
79372
+ output_dir: useZip ? join12(outputDir, `${filenameBase}.zip`) : join12(outputDir, filenameBase),
79304
79373
  files,
79305
79374
  code_embeds: codeEmbeds.length,
79306
79375
  transcript_embeds: transcriptEmbeds.length
@@ -80326,7 +80395,7 @@ function buildImagesAiDetectionSummary(uploadResult, filePath) {
80326
80395
  const classification = classifyImagesAiDetection(score);
80327
80396
  return {
80328
80397
  file: filePath,
80329
- filename: uploadResult.filename || basename3(filePath),
80398
+ filename: uploadResult.filename || basename4(filePath),
80330
80399
  content_type: uploadResult.content_type,
80331
80400
  embed_id: uploadResult.embed_id,
80332
80401
  deduplicated: uploadResult.deduplicated,
@@ -81357,7 +81426,7 @@ async function handleEmbeds(client, subcommand, rest, flags) {
81357
81426
  throw new Error("Embed version content was not available after local reconstruction.");
81358
81427
  }
81359
81428
  if (typeof flags.output === "string") {
81360
- writeFileSync9(flags.output, result.content, "utf-8");
81429
+ writeFileSync10(flags.output, result.content, "utf-8");
81361
81430
  if (flags.json === true) {
81362
81431
  printJson2({ ...result, output: flags.output });
81363
81432
  } else {
@@ -81641,12 +81710,12 @@ async function parseAccountImportFile(parserFormat, file, flags = {}) {
81641
81710
  const selectedSource = requestedSource;
81642
81711
  if (parserFormat === "generic") {
81643
81712
  if (selectedSource !== "gemini" && selectedSource !== "other") throw new Error("Generic account import requires --source gemini or --source other.");
81644
- return parseGenericImportBuffer(payload, basename3(file), selectedSource);
81713
+ return parseGenericImportBuffer(payload, basename4(file), selectedSource);
81645
81714
  }
81646
- if (parserFormat === "claude") return parseClaudeImportBuffer(payload, basename3(file), selectedSource);
81647
- if (parserFormat === "chatgpt") return parseChatGPTImportBuffer(payload, basename3(file), selectedSource);
81648
- if (parserFormat === "opencode") return parseOpenCodeImportBuffer(payload, basename3(file), selectedSource);
81649
- 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);
81650
81719
  }
81651
81720
  async function runAccountImport(client, parserFormat, file, flags) {
81652
81721
  if (parserFormat === "generic" && typeof flags.source !== "string") throw new Error("Generic account import requires --source gemini or --source other.");
@@ -82016,11 +82085,11 @@ function parseYamlScalar(value) {
82016
82085
  }
82017
82086
  async function saveDownloadedDocument(document, output) {
82018
82087
  const { mkdir: mkdir2, writeFile: writeFile2 } = await import("fs/promises");
82019
- const { join: join11, basename: basename4, dirname: dirname10 } = await import("path");
82088
+ const { join: join12, basename: basename5, dirname: dirname11 } = await import("path");
82020
82089
  const target = typeof output === "string" ? output : ".";
82021
- const filename = basename4(document.filename || "document.pdf");
82022
- const filePath = target.endsWith(".pdf") ? target : join11(target, filename);
82023
- 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 });
82024
82093
  await writeFile2(filePath, document.data);
82025
82094
  return filePath;
82026
82095
  }
@@ -82192,7 +82261,7 @@ async function handleFinance(client, subcommand, _rest, flags) {
82192
82261
  }
82193
82262
  function readFinanceCsvStatements(flags) {
82194
82263
  const paths = parseCsvFlag(flags.csv) ?? [];
82195
- return paths.map((filePath) => ({ filename: basename3(filePath), content: readFileSync12(filePath, "utf8") }));
82264
+ return paths.map((filePath) => ({ filename: basename4(filePath), content: readFileSync12(filePath, "utf8") }));
82196
82265
  }
82197
82266
  function buildFinanceCheckAccountsInput(flags, csvStatements, connectedAccount) {
82198
82267
  const input = {
@@ -82487,7 +82556,7 @@ async function promptPlainText(question) {
82487
82556
  }
82488
82557
  async function writeSecretFile(filePath, content, force = false) {
82489
82558
  const { mkdir: mkdir2, writeFile: writeFile2, stat: stat2 } = await import("fs/promises");
82490
- const { dirname: dirname10 } = await import("path");
82559
+ const { dirname: dirname11 } = await import("path");
82491
82560
  try {
82492
82561
  await stat2(filePath);
82493
82562
  if (!force) throw new Error(`${filePath} already exists. Use --force to overwrite.`);
@@ -82497,7 +82566,7 @@ async function writeSecretFile(filePath, content, force = false) {
82497
82566
  }
82498
82567
  if (error instanceof Error && !("code" in error)) throw error;
82499
82568
  }
82500
- await mkdir2(dirname10(filePath), { recursive: true });
82569
+ await mkdir2(dirname11(filePath), { recursive: true });
82501
82570
  await writeFile2(filePath, content, { mode: 384 });
82502
82571
  return filePath;
82503
82572
  }
@@ -85663,12 +85732,16 @@ function printSelfUpdateHelp() {
85663
85732
  openmates update [--version <version|tag>] [--package-manager <name>] [--dry-run] [--verbose] [--json]
85664
85733
  openmates upgrade [--version <version|tag>] [--package-manager <name>] [--dry-run] [--verbose] [--json]
85665
85734
 
85666
- 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.
85667
85738
 
85668
85739
  Options:
85669
- --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)
85670
85741
  --package-manager <name> npm, pnpm, yarn, or bun (default: detect, then npm)
85671
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
85672
85745
  --verbose Stream package-manager output during installation
85673
85746
  --json Output the update plan/result as JSON`);
85674
85747
  }
@@ -86475,7 +86548,7 @@ async function handleDocs(client, subcommand, rest, flags) {
86475
86548
  }
86476
86549
  if (subcommand === "download") {
86477
86550
  const { writeFile: writeFile2, mkdir: mkdir2 } = await import("fs/promises");
86478
- const { join: join11, dirname: dirname10 } = await import("path");
86551
+ const { join: join12, dirname: dirname11 } = await import("path");
86479
86552
  if (flags.all === true) {
86480
86553
  const outputDir = typeof flags.output === "string" ? flags.output : "./openmates-docs";
86481
86554
  const tree = await client.listDocs();
@@ -86484,8 +86557,8 @@ async function handleDocs(client, subcommand, rest, flags) {
86484
86557
  let count = 0;
86485
86558
  for (const slug2 of slugs) {
86486
86559
  const content2 = await client.getDoc(slug2);
86487
- const filePath = join11(outputDir, `${slug2}.md`);
86488
- await mkdir2(dirname10(filePath), { recursive: true });
86560
+ const filePath = join12(outputDir, `${slug2}.md`);
86561
+ await mkdir2(dirname11(filePath), { recursive: true });
86489
86562
  await writeFile2(filePath, content2, "utf-8");
86490
86563
  count++;
86491
86564
  process.stderr.write(`\r Downloaded ${count}/${slugs.length}`);
@@ -86557,8 +86630,8 @@ function isCliEntrypoint() {
86557
86630
  if (!entrypoint) return false;
86558
86631
  try {
86559
86632
  const invokedPath = realpathSync2(entrypoint);
86560
- const modulePath = realpathSync2(fileURLToPath2(import.meta.url));
86561
- 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);
86562
86635
  } catch {
86563
86636
  return false;
86564
86637
  }
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  resolveProjectContext,
12
12
  serializeToYaml,
13
13
  shouldRequireTrustedAccountGuard
14
- } from "./chunk-XKIFO4JO.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-XKIFO4JO.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.2",
3
+ "version": "0.18.0-alpha.3",
4
4
  "description": "OpenMates CLI and SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",