openmates 0.11.0-alpha.31 → 0.11.0-alpha.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,9 +39,10 @@ The CLI derives the web app URL from the API URL so pair-auth lands on the match
39
39
  | --- | --- |
40
40
  | Production | _(none)_ |
41
41
  | Dev server | `OPENMATES_API_URL=https://api.dev.openmates.org` |
42
- | Self-hosted | `OPENMATES_API_URL=https://api.example.com OPENMATES_APP_URL=https://example.com` |
42
+ | Installed self-hosted server | _(none after `openmates server install`)_ |
43
+ | Remote self-hosted server | `OPENMATES_API_URL=https://api.example.com` |
43
44
 
44
- You can also pass `--api-url <url>` per command. App-skill execution can use your logged-in session, `--api-key <key>`, or `OPENMATES_API_KEY`.
45
+ After `openmates server install`, fresh CLI commands default to that self-hosted server (`http://localhost:8000`) unless you already have a saved login session, set `OPENMATES_API_URL`, or pass `--api-url <url>`. App-skill execution can use your logged-in session, `--api-key <key>`, or `OPENMATES_API_KEY`.
45
46
 
46
47
  ## Safety Limits
47
48
 
@@ -874,6 +874,67 @@ function isSyncCacheFresh(maxAgeMs = 3e5) {
874
874
  return Date.now() - cache.syncedAt < maxAgeMs;
875
875
  }
876
876
 
877
+ // src/serverConfig.ts
878
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
879
+ import { homedir as homedir3 } from "os";
880
+ import { join as join2, resolve } from "path";
881
+ var STATE_DIR = join2(homedir3(), ".openmates");
882
+ var CONFIG_FILE = "server.json";
883
+ function ensureStateDir2() {
884
+ if (!existsSync3(STATE_DIR)) {
885
+ mkdirSync2(STATE_DIR, { recursive: true, mode: 448 });
886
+ }
887
+ return STATE_DIR;
888
+ }
889
+ function saveServerConfig(config) {
890
+ const dir = ensureStateDir2();
891
+ const filePath = join2(dir, CONFIG_FILE);
892
+ writeFileSync2(filePath, `${JSON.stringify(config, null, 2)}
893
+ `, { mode: 420 });
894
+ }
895
+ function loadServerConfig() {
896
+ const filePath = join2(STATE_DIR, CONFIG_FILE);
897
+ if (!existsSync3(filePath)) return null;
898
+ try {
899
+ return JSON.parse(readFileSync3(filePath, "utf-8"));
900
+ } catch {
901
+ return null;
902
+ }
903
+ }
904
+ function removeServerConfig() {
905
+ const filePath = join2(STATE_DIR, CONFIG_FILE);
906
+ if (existsSync3(filePath)) {
907
+ rmSync2(filePath);
908
+ }
909
+ }
910
+ var SOURCE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.yml");
911
+ var IMAGE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.selfhost.yml");
912
+ function isOpenMatesDir(dir) {
913
+ return existsSync3(join2(dir, SOURCE_COMPOSE_MARKER)) || existsSync3(join2(dir, IMAGE_COMPOSE_MARKER));
914
+ }
915
+ function resolveServerPath(flags) {
916
+ if (typeof flags.path === "string" && flags.path) {
917
+ const explicit = resolve(flags.path);
918
+ if (!isOpenMatesDir(explicit)) {
919
+ throw new Error(
920
+ `${explicit} does not appear to be an OpenMates installation (missing ${SOURCE_COMPOSE_MARKER} or ${IMAGE_COMPOSE_MARKER}).`
921
+ );
922
+ }
923
+ return explicit;
924
+ }
925
+ const config = loadServerConfig();
926
+ if (config?.installPath && isOpenMatesDir(config.installPath)) {
927
+ return config.installPath;
928
+ }
929
+ const cwd = process.cwd();
930
+ if (isOpenMatesDir(cwd)) {
931
+ return cwd;
932
+ }
933
+ throw new Error(
934
+ "No OpenMates installation found.\nRun 'openmates server install' to set up a new server, or use --path <dir>."
935
+ );
936
+ }
937
+
877
938
  // src/ws.ts
878
939
  import { createRequire } from "module";
879
940
  var require2 = createRequire(import.meta.url);
@@ -1910,9 +1971,14 @@ function deriveWebOrigin(apiUrl) {
1910
1971
  const url = new URL(apiUrl);
1911
1972
  if (url.hostname === "api.dev.openmates.org") {
1912
1973
  url.hostname = "app.dev.openmates.org";
1974
+ } else if (url.hostname === "api.openmates.org") {
1975
+ url.hostname = "openmates.org";
1913
1976
  } else {
1914
- url.hostname = url.hostname.replace(/^api\./, "");
1977
+ url.hostname = url.hostname.replace(/^api\./, "app.");
1915
1978
  }
1979
+ url.pathname = "";
1980
+ url.search = "";
1981
+ url.hash = "";
1916
1982
  url.port = "";
1917
1983
  return url.origin;
1918
1984
  } catch {
@@ -2382,24 +2448,50 @@ var MATE_NAMES = {
2382
2448
  general_knowledge: "George",
2383
2449
  onboarding_support: "Suki"
2384
2450
  };
2385
- var DEFAULT_API_URL = process.env.OPENMATES_API_URL ?? "https://api.openmates.org";
2451
+ var CLOUD_API_URL = "https://api.openmates.org";
2452
+ var DEFAULT_API_URL = process.env.OPENMATES_API_URL ?? CLOUD_API_URL;
2386
2453
  var SETTINGS_GET_RATE_LIMIT_RETRY_MS = 61e3;
2387
2454
  var SKILL_TASK_POLL_INTERVAL_MS = 2e3;
2388
2455
  var SKILL_TASK_POLL_TIMEOUT_MS = 3e5;
2456
+ function normalizeOrigin(url) {
2457
+ url.pathname = "";
2458
+ url.search = "";
2459
+ url.hash = "";
2460
+ return url.toString().replace(/\/$/, "");
2461
+ }
2462
+ function isLocalHost(hostname) {
2463
+ return ["localhost", "127.0.0.1", "::1"].includes(hostname);
2464
+ }
2465
+ function loadDefaultServerApiUrl() {
2466
+ const config = loadServerConfig();
2467
+ return config?.apiUrl?.replace(/\/$/, "") ?? null;
2468
+ }
2389
2469
  function deriveAppUrl(apiUrl) {
2390
2470
  if (process.env.OPENMATES_APP_URL) {
2391
2471
  return process.env.OPENMATES_APP_URL.replace(/\/$/, "");
2392
2472
  }
2393
- if (apiUrl.includes("api.dev.openmates.org")) {
2394
- return "https://app.dev.openmates.org";
2473
+ const serverAppUrl = loadServerConfig()?.appUrl;
2474
+ if (serverAppUrl && apiUrl.replace(/\/$/, "") === loadDefaultServerApiUrl()) {
2475
+ return serverAppUrl.replace(/\/$/, "");
2395
2476
  }
2396
- if (apiUrl.includes("api.openmates.org")) {
2477
+ try {
2478
+ const url = new URL(apiUrl);
2479
+ if (url.hostname === "api.dev.openmates.org") {
2480
+ return "https://app.dev.openmates.org";
2481
+ }
2482
+ if (url.hostname === "api.openmates.org") {
2483
+ return "https://openmates.org";
2484
+ }
2485
+ if (isLocalHost(url.hostname)) {
2486
+ return "http://localhost:5173";
2487
+ }
2488
+ if (url.hostname.startsWith("api.")) {
2489
+ url.hostname = `app.${url.hostname.slice(4)}`;
2490
+ }
2491
+ return normalizeOrigin(url);
2492
+ } catch {
2397
2493
  return "https://openmates.org";
2398
2494
  }
2399
- if (apiUrl.includes("localhost")) {
2400
- return "http://localhost:5173";
2401
- }
2402
- return "https://openmates.org";
2403
2495
  }
2404
2496
  var CLI_DEVICE_NAME_PREFIX = "OpenMates CLI";
2405
2497
  var BLOCKED_SETTINGS_MUTATE_PATHS = /* @__PURE__ */ new Set([
@@ -2420,7 +2512,7 @@ var OpenMatesClient = class _OpenMatesClient {
2420
2512
  http;
2421
2513
  constructor(options = {}) {
2422
2514
  const diskSession = options.session ?? this.getValidSessionFromDisk();
2423
- this.apiUrl = (options.apiUrl ?? process.env.OPENMATES_API_URL ?? diskSession?.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
2515
+ this.apiUrl = (options.apiUrl ?? process.env.OPENMATES_API_URL ?? diskSession?.apiUrl ?? loadDefaultServerApiUrl() ?? DEFAULT_API_URL).replace(/\/$/, "");
2424
2516
  this.session = diskSession;
2425
2517
  this.http = new OpenMatesHttpClient({
2426
2518
  apiUrl: this.apiUrl,
@@ -5838,9 +5930,9 @@ var OutputRedactor = class {
5838
5930
  };
5839
5931
 
5840
5932
  // src/fileEmbed.ts
5841
- import { readFileSync as readFileSync3, statSync, existsSync as existsSync3 } from "fs";
5842
- import { basename, extname, resolve } from "path";
5843
- import { homedir as homedir3 } from "os";
5933
+ import { readFileSync as readFileSync4, statSync, existsSync as existsSync4 } from "fs";
5934
+ import { basename, extname, resolve as resolve2 } from "path";
5935
+ import { homedir as homedir4 } from "os";
5844
5936
  import { createHash as createHash4 } from "crypto";
5845
5937
  var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
5846
5938
  var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -6045,9 +6137,9 @@ function processEnvFileZeroKnowledge(content) {
6045
6137
  }
6046
6138
  function resolvePath(filePath) {
6047
6139
  if (filePath.startsWith("~/")) {
6048
- return resolve(homedir3(), filePath.slice(2));
6140
+ return resolve2(homedir4(), filePath.slice(2));
6049
6141
  }
6050
- return resolve(filePath);
6142
+ return resolve2(filePath);
6051
6143
  }
6052
6144
  function processFiles(filePaths, redactor) {
6053
6145
  const embeds = [];
@@ -6057,7 +6149,7 @@ function processFiles(filePaths, redactor) {
6057
6149
  const resolvedPath = resolvePath(rawPath);
6058
6150
  const filename = basename(resolvedPath);
6059
6151
  const ext = getExt(filename);
6060
- if (!existsSync3(resolvedPath)) {
6152
+ if (!existsSync4(resolvedPath)) {
6061
6153
  errors.push({ path: rawPath, error: "File not found" });
6062
6154
  continue;
6063
6155
  }
@@ -6123,7 +6215,7 @@ function processFiles(filePaths, redactor) {
6123
6215
  }
6124
6216
  function processCodeFile(filePath, filename, redactor) {
6125
6217
  try {
6126
- let content = readFileSync3(filePath, "utf-8");
6218
+ let content = readFileSync4(filePath, "utf-8");
6127
6219
  let secretsRedacted = false;
6128
6220
  let zeroKnowledge = false;
6129
6221
  if (isEnvFile(filename)) {
@@ -7544,69 +7636,6 @@ import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readF
7544
7636
  import { createInterface as createInterface2 } from "readline";
7545
7637
  import { homedir as homedir5 } from "os";
7546
7638
  import { join as join3, resolve as resolve3 } from "path";
7547
-
7548
- // src/serverConfig.ts
7549
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
7550
- import { homedir as homedir4 } from "os";
7551
- import { join as join2, resolve as resolve2 } from "path";
7552
- var STATE_DIR = join2(homedir4(), ".openmates");
7553
- var CONFIG_FILE = "server.json";
7554
- function ensureStateDir2() {
7555
- if (!existsSync4(STATE_DIR)) {
7556
- mkdirSync2(STATE_DIR, { recursive: true, mode: 448 });
7557
- }
7558
- return STATE_DIR;
7559
- }
7560
- function saveServerConfig(config) {
7561
- const dir = ensureStateDir2();
7562
- const filePath = join2(dir, CONFIG_FILE);
7563
- writeFileSync2(filePath, `${JSON.stringify(config, null, 2)}
7564
- `, { mode: 420 });
7565
- }
7566
- function loadServerConfig() {
7567
- const filePath = join2(STATE_DIR, CONFIG_FILE);
7568
- if (!existsSync4(filePath)) return null;
7569
- try {
7570
- return JSON.parse(readFileSync4(filePath, "utf-8"));
7571
- } catch {
7572
- return null;
7573
- }
7574
- }
7575
- function removeServerConfig() {
7576
- const filePath = join2(STATE_DIR, CONFIG_FILE);
7577
- if (existsSync4(filePath)) {
7578
- rmSync2(filePath);
7579
- }
7580
- }
7581
- var SOURCE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.yml");
7582
- var IMAGE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.selfhost.yml");
7583
- function isOpenMatesDir(dir) {
7584
- return existsSync4(join2(dir, SOURCE_COMPOSE_MARKER)) || existsSync4(join2(dir, IMAGE_COMPOSE_MARKER));
7585
- }
7586
- function resolveServerPath(flags) {
7587
- if (typeof flags.path === "string" && flags.path) {
7588
- const explicit = resolve2(flags.path);
7589
- if (!isOpenMatesDir(explicit)) {
7590
- throw new Error(
7591
- `${explicit} does not appear to be an OpenMates installation (missing ${SOURCE_COMPOSE_MARKER} or ${IMAGE_COMPOSE_MARKER}).`
7592
- );
7593
- }
7594
- return explicit;
7595
- }
7596
- const config = loadServerConfig();
7597
- if (config?.installPath && isOpenMatesDir(config.installPath)) {
7598
- return config.installPath;
7599
- }
7600
- const cwd = process.cwd();
7601
- if (isOpenMatesDir(cwd)) {
7602
- return cwd;
7603
- }
7604
- throw new Error(
7605
- "No OpenMates installation found.\nRun 'openmates server install' to set up a new server, or use --path <dir>."
7606
- );
7607
- }
7608
-
7609
- // src/server.ts
7610
7639
  var SOURCE_COMPOSE_FILE = join3("backend", "core", "docker-compose.yml");
7611
7640
  var IMAGE_COMPOSE_FILE = join3("backend", "core", "docker-compose.selfhost.yml");
7612
7641
  var COMPOSE_OVERRIDE = join3("backend", "core", "docker-compose.override.yml");
@@ -7779,6 +7808,15 @@ function setEnvVar(content, name, value) {
7779
7808
  function setEnvIfEmpty(content, name, value) {
7780
7809
  return getEnvVar(content, name) ? content : setEnvVar(content, name, value);
7781
7810
  }
7811
+ function firstCsvValue(value) {
7812
+ return value.split(",").map((item) => item.trim()).find(Boolean) ?? "";
7813
+ }
7814
+ function deriveSelfHostCliUrls(envContent) {
7815
+ return {
7816
+ apiUrl: firstCsvValue(getEnvVar(envContent, "VITE_API_URL")) || "http://localhost:8000",
7817
+ appUrl: firstCsvValue(getEnvVar(envContent, "PRODUCTION_URL")) || "http://localhost:5173"
7818
+ };
7819
+ }
7782
7820
  async function fetchText(url) {
7783
7821
  const response = await fetch(url);
7784
7822
  if (!response.ok) {
@@ -8014,6 +8052,7 @@ async function serverInstall(flags) {
8014
8052
  const imageTag = typeof flags["image-tag"] === "string" ? flags["image-tag"] : getDefaultImageTag();
8015
8053
  console.error(`Preparing OpenMates image-mode install at ${installPath}...`);
8016
8054
  await writeImageModeRuntimeFiles(installPath, imageTag);
8055
+ const cliUrls2 = deriveSelfHostCliUrls(readFileSync5(join3(installPath, ".env"), "utf-8"));
8017
8056
  try {
8018
8057
  exec("docker network create openmates", installPath);
8019
8058
  } catch {
@@ -8023,7 +8062,8 @@ async function serverInstall(flags) {
8023
8062
  installedAt: Date.now(),
8024
8063
  composeProfile: "core",
8025
8064
  installMode: "image",
8026
- imageTag
8065
+ imageTag,
8066
+ ...cliUrls2
8027
8067
  });
8028
8068
  if (flags.json === true) {
8029
8069
  printJson({ command: "install", status: "success", path: installPath, mode: "image", imageTag });
@@ -8037,6 +8077,8 @@ OpenMates installed at ${installPath}`);
8037
8077
  console.log(" 2. Open http://localhost:5173");
8038
8078
  if (firstInvite) console.log(` 3. Sign up with invite code: ${firstInvite}`);
8039
8079
  console.log(" 4. After signup, make yourself admin: openmates server make-admin your@email.com");
8080
+ console.log(`
8081
+ CLI default API: ${cliUrls2.apiUrl}`);
8040
8082
  console.log("\nOptional: edit .env first to add LLM provider API keys. Source builds are available with --from-source.");
8041
8083
  }
8042
8084
  return;
@@ -8079,11 +8121,14 @@ OpenMates installed at ${installPath}`);
8079
8121
  console.error("Setup script failed. Check the output above for details.");
8080
8122
  process.exit(setupCode);
8081
8123
  }
8124
+ const envPath = join3(installPath, ".env");
8125
+ const cliUrls = deriveSelfHostCliUrls(existsSync5(envPath) ? readFileSync5(envPath, "utf-8") : "");
8082
8126
  saveServerConfig({
8083
8127
  installPath,
8084
8128
  installedAt: Date.now(),
8085
8129
  composeProfile: "core",
8086
- installMode: "source"
8130
+ installMode: "source",
8131
+ ...cliUrls
8087
8132
  });
8088
8133
  if (flags.json === true) {
8089
8134
  printJson({ command: "install", status: "success", path: installPath, mode: "source" });
@@ -8094,6 +8139,8 @@ OpenMates installed at ${installPath}`);
8094
8139
  console.log(" 1. Run: openmates server start");
8095
8140
  console.log(" 2. Open http://localhost:5173");
8096
8141
  console.log(" 3. After signup, make yourself admin: openmates server make-admin your@email.com");
8142
+ console.log(`
8143
+ CLI default API: ${cliUrls.apiUrl}`);
8097
8144
  console.log("\nOptional: edit .env first to add LLM provider API keys. Without keys, the web app and backend still start, but AI model processing is unavailable.");
8098
8145
  }
8099
8146
  }
@@ -45138,7 +45185,7 @@ Commands:
45138
45185
 
45139
45186
  Flags:
45140
45187
  --json Output raw JSON instead of formatted output
45141
- --api-url <url> Override API base URL (default: https://api.openmates.org)
45188
+ --api-url <url> Override API base URL (default: installed self-host server, then https://api.openmates.org)
45142
45189
  --api-key <key> Optional API key override (or set OPENMATES_API_KEY)
45143
45190
  --help Show contextual help for any command`);
45144
45191
  }
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getExtForLang,
4
4
  serializeToYaml
5
- } from "./chunk-3TZYVNWL.js";
5
+ } from "./chunk-NI7XPZBV.js";
6
6
  import "./chunk-AXNRPVLE.js";
7
7
  export {
8
8
  getExtForLang,
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  getExtForLang,
8
8
  parseNewChatSuggestionText,
9
9
  serializeToYaml
10
- } from "./chunk-3TZYVNWL.js";
10
+ } from "./chunk-NI7XPZBV.js";
11
11
  import "./chunk-AXNRPVLE.js";
12
12
  export {
13
13
  MATE_NAMES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmates",
3
- "version": "0.11.0-alpha.31",
3
+ "version": "0.11.0-alpha.32",
4
4
  "description": "OpenMates CLI and SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",